domingo, 26 de abril de 2009

Controle de versão: Introdução II

Se você ainda não leu a primeira parte sugiro que confira o post “Controle de versão: Introdução I” antes de continuar.

Agora que sabemos o que é um branch e como funcionam, podemos seguir um pouco mais e aprendermos a padronização da estrutura de diretórios do controle de versões.

Oficialmente é recomendado que cada projeto seja criado em um repositório exclusivo, para que ele possa evoluir sem interferir nos demais projetos.

Em cada repositório, devem-se criar três pastas, segundo a recomendação oficial:

  • trunk
  • branches
  • tags

Cada pasta tem uma finalidade muito específica e vamos abordar duas hoje (não vamos abordar a tags porque existirá um post apenas para isto).

Inicialmente, vamos para a trunk que é a mais prática de se aprender, justamente por ser a mais comum de se trabalhar.

No diretório trunk estará, de forma simplificada, o código mais recente do projeto. Sim, é pura e simplesmente isto.

Será nesta pasta que os seus programadores irão fazer o checkin do código que foi recentemente alterado, e será dela que o último código deverá ser obtido (geral).

No entanto, imaginem o que aconteceria se um ou mais funcionários receberam a tarefa de criar uma alteração grande. Por exemplo, migrar o sistema inteiro de arquivo de dados (exemplo: TXT ou algo do tipo, mesmo que mais evoluído) para um SGBD.

Se eles submeterem as alterações ali constantemente, pode acabar gerando várias falhas em clientes ou repassar código não-final para outros programadores.

A primeira solução seria uma gambiarra, mas é proposta pelo próprio tutorial do Subversion: os programadores se isolarem (nao realizarem checkin). Pulando alguns problemas que eles levantam, vamos diretamente para dois pontos críticos:

  1. O computador deles geralmente é mais suceptível a falhas que o servidor, ou seja, o risco de se danificar o código e perder todo o trabalho será elevado.
  2. Se alguma outra alteração for realizada no sistema no período em que eles não realizaram contato com o sistema CVS a versão deles se tornará defasada e na hora final de checkin pode gerar imprevistos, como incompatibilidade entre métodos que foram alterados durante este tempo.

É nesta hora que chega o segundo diretório de hoje, o branches.

Nele será criada uma nova versão do projeto, isolada, para cada programador que estiver fazendo uma modificação maior e que não queira afetar os demais programadores, pelo momento. Assim ele pode acompanhar a evolução do sistema (pois está realizando checkin/checkout do código-fonte normalmente), terá menos chance de perder ou danificar o código, evitará imprevistos de última hora durante o processo de merge do código alterado.

De fato, o diretório branches contém muito mais que isto. 
Um exemplo é uma boa-prática realizada por alguns projetos onde a versão testada e estável está em branches/stable. Assim, o diretório trunk conterá o código mais recente, porém, ainda não totalmente testado. Assim que testado e que a qualidade seja comprovada, ele migra para o branches/stable.

Versões personalizadas de cada cliente podem compor um ramo mais complexo, surgindo em branches/projeto_1 por exemplo, e contendo a estrutura trunk/branches subordinada ao mesmo.

sábado, 25 de abril de 2009

Controle de versão: Introdução I

Pessoal, depois de meu sumiço, finalmente estou de volta. A falta de tempo, cansaço excessivo e preguiça acumulada me deixaram inativo aqui por algum tempo. Agora estou realmente de volta à ativa e continuando com o blog diariamente.

Dando continuidade à série que se iniciou no post anterior (Controle de versão), agora vamos aprender alguns conceitos sobre o controle de versão.

O guia será montado de forma bem devagar porque é importante que vocês entendam como funciona perfeitamente bem o CVS (controle de versão) ou, caso contrário, poderão causar falhas no programa que estiverem utilizando ou até mesmo perder suas alterações no código.

Primeiramente, vamos supor uma árvore. No tronco, a parte principal da árvore. A partir do tronco surgem os galhos primários, destes, os galhos secundários, e assim por diante.

No sistema de controle de versões, as versões são criadas de forma bem parecida.

Quando você submete (checkin) de um código ele gera uma nova versão que irá atualizar o repositório (local onde está a versão que se está trabalhando). Seguindo a analogia, coonsidere que estamos trabalhando com a versão principal (tronco). Ao realizar o checkin, o tronco se expande (sobe), crescendo.

No entanto, vamos supor que um cliente solicita uma determinada alteração, totalmente específica para ele. Não compensaria, portanto, alterar o sistema por completo, já que os outros usuários não vão querer a modificação específica. Nesta caso, criamos uma versão exclusiva, um galho separado (na analogia), que se chama BRANCH.

No controle de versão cada um dos “galhos” recebe o nome de Branch. É possível se ter, como na árvore, inúmeros branches e deles, criar-se outros branches, e assim por diante.

Voltando ao exemplo, criaríamos um branch baseado no branch original, e, a partir de então, este branch seguiria seu próprio caminho, evoluindo de acordo com alterações feitas nele.

No entanto, suponhamos um BUG detectado em uma determinada parte do programa comum a todos os usuários inclusive este com a versão diferenciada. Não vou explicar ainda COMO realizar isto mas já adianto que é possível replicar uma determinada alteração nos branches-filhos, o que facilitaria muito nosso trabalho.

A figura abaixo (terceira figura do blog *-*) ilustra o nosso exemplo:

            Branches primario e secundario

Créditos: Anderson Luiz Mendes Matos, 2009. Título: Branches CVS.
Esta imagem pode ser livremente reproduzida mas não alterada.

 

Se repararem, o branch principal e o secundário estão no presente (ponta da seta) separados entre si, funcionando como que completamente isolados. No entanto, eles compartilham partes em comum, que pode ser vista na hora em que o branch secundário se separa do primário.

Repetindo as palavras do próprio SVN, “não se preocupe com o crescimento do repositório pois não são criadas cópias físicas dos arquivos. o sistema armazena apenas a cópia original e as diferenças (alterações, DIFF) que esta cópia sofreu, eviando repetição desnecessária. Na hora de realizar checkout é feita a comparação e a partir da diferença armazenada é gerada a versão final do arquivo, correspondente à última versão de checkin.”.

Não vou prolongar o post por hoje, basta que vocês tenham em mente que no controle de versões são criados os branches e deles, surge o que será controlado. Estes branches (primários) podem dar origem a outros (secundários), e assim indefinidamente, para atender as necessidades específicas de cada ambiente.

Também é importante lembrar que é possível “matar” um branch, voltando ele como parte do código original (merge), e vice-versa. Isso permite espalhar atualizações de código, alterações ou modificações mais profundas.

segunda-feira, 13 de abril de 2009

Controle de versão: histórico dos arquivos

Já tiveram um sério problema de saber o que mudou na alteração que o funcionário Asdrúbal de Oliveira fez na semana passada? E o que os demais fizeram, também na mesma data?

E aquele probleminha incômodo de duas pessoas alterando um mesmo código?

Bom pessoal, estes e vários outros problemas são cotidianos e precisam ser corrigidos se a empresa tem a perspectiva de crescimento. Isto é fato. Mas como fazer?

Subversion é um programa complexo, antigo e extremamente funcional. É, hoje, sem sombra de dúvidas, um dos sistemas de controle de versão (SVN – CVS) mais utilizados mundialmente, lado a lado com outros como Mercurial, Bazaar e vários outros.

Basicamente temos um programa que mantém um histórico de tudo o que foi submetido para ele armazenar. Ou seja, se você submeter um arquivo TXT ele, tendo uma versão original, criará uma entrada dizendo quais linhas foram alteradas, quando e por quem, incluindo uma mensagem (opcional) que o responsável por submeter o arquivo pode colocar.

Vale a pena conferir: http://subversion.tigris.org

Existem ferramentas para ambos ambientes Windows e Linux. 
Ele funciona em conjunto com o Apache, podendo disponibilizar o repositório (local dos arquivos) via HTTP ou HTTPS. Também permite aceitar submissões (PUT) através do Apache (Cuidado! Isto comente funciona corretamente em versões 32 bits. Encontrei alguns erros em ambientes x64 para este recurso).

Uma boa prática é ler o guia introdutório que, apesar de estar em inglês, está bem claro e legível. O capítulo 1 explica detalhadamente como funciona um sistema CVS (Controle de Versão) como o SVN, explica os pontos abordados (alterações simultâneas em um arquivo, várias versões do mesmo arquivo, enfim…). 
De forma geral, bastará instalar o Subversion, um cliente (recomendo, para Windows, o TortoiseSVN) e aprender a trabalhar fazendo checkout (download) e checkin (upload) do código para um servidor central.

Vantagens? Várias:

  • Evita que, quando duas pessoas submetam um mesmo arquivo, prevaleça apenas a versão do que submeteu por último. Existe um complexo controle aqui mas de forma geral, se o arquivo for editável (texto) o SVN mostra as incompatibilidades e solicita uma açado. Em caso de arquivos binários (imagens, executáveis, dll, etc) ele pergunta por uma ação (sobrescrever, por exemplo) se estiver disponível ou cancela o update, caso seja configurado para não permitir este caso.
  • Permite que você possa controlar diferentes versões de um mesmo arquivo. De forma geral, é possível obter uma versão passada bastando fornecer o número da versão desejada.
  • Permite você centralizar o código, permitindo que as pessoas tenham acesso ao mesmo de forma organizada. Também permite, logicamente, um controle de usuários para TODOS os códigos armazenados, bem como um controle de usuários POR PROJETO armazenado no SVN.

Isso dentre várias opções.

É um modelo aprovado, importante e bem reconhecido. Vale a pena estudar um pouco, aprender como funciona. Inclusive se você trabalhar sozinho(a). Imaginou ter, ao mesmo tempo, várias versões ligeiramente distintas do mesmo código (exemplo: vários clientes com pequenas alterações entre eles no mesmo código) e replicar uma alteração comum para todas as diversas versões, preservando essa individualidade?

quarta-feira, 8 de abril de 2009

Threads: execução simultânea?

Já repararam que alguns programas costumam travar após se clicar em um botão?

Já perceberam que algumas ações demoradas, como, por exemplo, fazer um download de um arquivo grande, pode, em algumas versões do Windows, deixar a aplicação esbranquiçada e com o lindo título de “Não respondendo…”?

Não, isto não é uma falha do Windows. Muito menos da Internet. Isto é um erro muito comum de nós, programadores. De forma geral, dificilmente separamos Threads de execução e quando o fazemos, nem sempre OBEDECEMOS esta separação.

Uma boa definição de Thread: 
Considerando que a aplicação como um todo seja um livro, Thread seria cada página do livro. Algumas, maiores (dobradas) que as outras, algumas com mais conteúdo, mas ainda sim, todas são independentes entre-si e juntas, formam o livro.

Outra forma de compreender Thread é pensando nelas como um ambiente separado de execução. Basicamente é isto. Thread é um ambiente, uma camada na qual o programa está executando ou será executado. Você pode abrir várias Threads, para evitar alguns problemas como os famosos botões afundados quando se clica e a ação demora muito tempo para ser finalizada.

Thread, na realidade, é bem mais poderosa que isto.

A melhor forma de entender o poder de uma Thread é entender COMO DEVERIA ser feita a aplicação (nossa! outra imagem!):

Thread-1

Créditos: Anderson Luiz Mendes Matos, 2009. Título: Threads.
Esta imagem pode ser livremente reproduzida mas não alterada.

 

É importante perceber que existe uma Thread “mãe” chamada Event Dispatcher (Iniciadora de Eventos, ou apenas Thread Principal). Ela representa a primeira e principal Thread do programa, onde DEVE ficar APENAS a interface gráfica.

Isto mesmo, é nela (Event Dispatcher) que fica a sua interface, o seu contato com o usuário, a sua interface.

As demais Threads (T1, T2, T3, …, Tn) são Threads criadas durante a execução, para executar ações diversas. Idealmente, todas as classes que fossem Model (padrão MVC) deveriam ter seus métodos chamados em Threads isoladas, mas isto gerão não é feito (complexidade, dificuldade de troca de informações entre Threads, preguiça, enfim…). De forma geral, o mais importante é colocar em Threads isoladas todos os recursos que precisem esperar algo (por exemplo, que precisem monitorar um determinado local no HD esperando que um determinado arquivo seja criado) ou que seus métodos sejam tão demorados que level mais de 0,5 segundos para serem executados, o que pode ocasionar em travamentos na interface do usuário.

“Ah, mas o botão tem que ficar travado. Imagine se o usuário clicar várias vezes no mesmo botão e ele execuar várias vezes o mesmo processo?”. Isto é “desculpa pra boi dormir”. Um programa bem feito pode facilmente bloquear o botão (e APENAS o botão), executar a Thread nova e a própria Thread, ao ser finalizada, desbloqueia o botão, evitando assim que um mesmo método seja executado múltiplas vezes.

“E como eu faço para que Threads diferentes não acessem o mesmo arquivo ao mesmo tempo?”. Locks. Toda linguagem tem sua forma de aplicar um lock ao arquivo. Se você vai LER apenas o arquivo, não há maiores problemas. Se a informação é volátil (por exemplo, um número que, de tempos em tempos pode ter seu valor alterado ou outra Thread) o ideal é implementar uma Thread que verifique o conteúdo do arquivo de X em X milissegundos (dependendo da volatilidade do conteúdo). Esta Thread repassa o valor lido para outra Thread (por exemplo, a Event Dispatcher, exibindo o conteúdo do número). 
Se o problema é gravar no arquivo, o ideal é através de Locks (Cursores/CURSOR). Assim você garante a integridade do arquivo.

Mas então, porque é interessante usar Threads?

Sua principal força está em executar partes do código distintas, ao mesmo tempo. 
Você pode, pode exemplo, executar dois ou mais downloads (exemplo de um sistema de controle de downloads) simultaneamente, ou várias partes de um mesmo download. 
Pode, em outro caso (exemplo de um sistema de geração de boletos bancários) permitir ao usuário que ele clique em “Imprimir boletos” (o que, no exemplo, geraria uma impressão de 400 boletos frente-e-verso), fechar a tela e continuar trabalhando em outra coisa, até que a impressão estivesse concluída.

Enfim, Threads são fortes em execução paralela.

Mas cuidado com as Threads. Elas não possuem QUALQUER garantia. Por exemplo, uma Thread que esteja em “sleep” (adormecida, pausada) pode simplesmente acordar antes da hora, se o sistema operacional achar que ela morreu. Outro detalhe é que iniciar uma Thread A antes de uma Thread B não garante que A seja finalizada antes. Nem mesmo se A possuir maior prioridade. Dependerá apenas da boa vontade do processador, que, de forma geral, tenta ser aleatório quanto à execução das Threads. Elas não são garantidas de não “morrerem” (travarem), embora isso seja mais um problema de programação que de execução.

Threads são amigas. Chatas, teimosas, complicadas, mas amigas. 
Linguagens mais recentes como C# ou Java (nem tão recente assim) dão um forte enfoque às Threads. Sistemas mais antigos, como Delphi, C++, Clarion e outros, possuem foco em outros pontos. 
De forma geral, cada linguagem utiliza Threads de seu próprio jeito, mas é importante que o programador saiba utilizá-las com sabedoria e com calma. Threads em excesso podem causar sérios problemas em DEBUG.

terça-feira, 7 de abril de 2009

MVC: Essa moda ainda vai pegar você.

Toda vez que mudamos de linguagem é a mesma velha história:

  • Orientada a Objetos
  • Reaproveitamento de Código
  • Facilidade de Migração
  • Facilidade de Debug e Correção de Erros

Mas pessoal, convenhamos, quando a gente migra de linguagem o que menos vemos é isto. Parece mais discurso de político, não é mesmo?

Pois é, mas isto somente ocorre com quem está desenvolvendo de forma ANTIGA em ambiente NOVO. Seja sincero, não aqui no Blog porque não quero ninguém pagando mico, mas consigo mesmo(a). Você desenvolve de forma errada. De forma geral, se você reparar no seu trabalho, parece que continua desenvolvendo em uma linguagem Procedural, não é mesmo? Ou em uma Orientada à Gambiarra, estou certo?

Pessoal, há algum tempo resolveram criar um modelo de desenvolvimento. Uma estrutura que permitiria EFETIVAMENTE criar programas reaproveitáveis, códigos mais simples, bem mais organizados, de uma forma extremamente produtiva e (pasmem!) muito mais simples do que seria antigamente.

E o melhor: O padrão está tão bem documentado e foi tão bem elaborado que pode ser usado em qualquer linguagem de programação, embora seja especialmente produtivo para linguagens OO.

Observem o modelo MVC de pertinho (nossa! uma imagem!):

MVC-1

Créditos: Anderson Luiz Mendes Matos, 2009. Título: Modelo MVC. 
Esta imagem pode ser livremente reproduzida mas não alterada.

De forma geral, temos três entidades pertencentes ao modelo MVC:

  1. Controller ou Controlador: Representa (óbvio) o “C” do “MVC”. Este componente representa a parte controladora da aplicação. Tá, eu sei que ficou redundante. Digamos que o Controller é responsável, em uma aplicação Desktop (standalone) por CHAMAR os métodos, por INSTANCIAR as devidas classes, por DECIDIR o que será feito naquele momento, enfim, ele não FAZ as coisas acontecerem, ele apenas COORDENA o processo para que ele ocorra normalmente.
  2. Model ou Modelagem de Negócio: Mais óbvio ainda, representa o “M” de “MVC”. O Model é quem vai EXECUTAR as tarefas. Por exemplo, é quem vai pegar uma informação no SGBD, é quem vai calcular um somatório, é quem vai conferir se o CPF é válido, é quem vai gerar o PDF conforme solicitado, enfim, ele FAZ as coisas. Somente isto. Somente FAZ. Ele não sabe o que tem a ser feito, ele apenas sabe como fazer.
  3. View ou Interface: É, logicamente, o “V” do “MVC” e é encarregado de receber um recurso “raw” (sem formatação, sem qualquer preparo, somente o dado puro) e exibí-lo de forma organizada, correta, “bonitinha”, estruturada.

Veja abaixo um exemplo do funcionamento do MVC:

  1. Usuário clica no menu “Gerar relatório de todos os usuários”.
  2. O Controller decide qual tela irá exibir, no caso, ele vai, antes de qualquer outra coisa, perguntar se o relatório vai ser em impressora ou PDF.
  3. O usuário decide por PDF e o Controller então “solicita que a interface se apresente”. O correto seria falar isso mas soa estranho, então de agora em diante eu vou dizer apenas “exibe a interface de …”.
  4. O usuário digita qualquer que sejam os dados necessários ao relatório (exemplo: filtros para não ser necessário imprimir todos os registros).
  5. Quando o usuário clicar em “Imprimir” o Controller é informado e, então, solicita ao Model que processe as informações e retorne os dados do relatório.
  6. O Model relativo ao relatório (exemplo: uma classe Java, um embed em Clarion, uma unit em Delphi, enfim…) recebe os parâmetros vindos da interface e processa o relatório, buscando os dados relevantes no SGBD e organizando-os, por exemplo, em uma matriz.
  7. O Model retorna o resultado para o Controller que, então, chama outro Model, agora responsável por gerar o PDF. Este Model é capaz de receber, por exemplo, uma matriz e, sabendo que se trata de uma matriz ele monta um PDF padrão para relatórios. Após o PDF montado e pronto, o Model pode decidir entre salvar o PDF (por exemplo) ou exibí-lo em tela. Suponhamos que ele decida exibí-lo. Assim sendo, ele devolve o PDF para o Controller.
  8. O Controller, por último, inicializa e exibe a interface de apresentação de PDFs. Esta tela possui o único trabalho de receber um arquivo PDF e exibí-lo (renderização). Mais nada.
  9. Fim da jornada. O usuário feliz e saltitante pode ver seu relatório em PDF.

Simples? Nem tanto. A idéia é simples, mas a implementação é um pouco difícil. Não na questão de complexidade, mas na nossa própria teimosia. “Ah, eh só uma variável, vou por ela aqui, depois eu arrumo direitinho”. Se isto acontecer, pode saber que você acabou de quebrar o MVC. Para sempre. Tenha CERTEZA que você nunca vai voltar para arrumar esta pequenina quebra, principalmente se o sistema compilar e funcionar corretamente.

O MVC é um padrão fundamental hoje em dia, para qualquer desenvolvimento de qualidade. Seus principais benefícios são:

  • Isolamento da camada de negócios e da camada de interface. Isto permite coisas bem interessantes, tais como equipes distintas (uma trabalhando com design de interfaces/usabilidade e outra trabalhando com código apenas), permite que a interface possa ser facilmente alterada (por exemplo, migrar o programa para WEB nunca ficou tão simples. Em algumas linguagens, como Java ou .NET, bastaria trocar a interface desktop por páginas HTML + CSS + JavaScript/Ajax).
  • Este isolamento também favorece o desenvolvimento modular, ou seja, você pode criar bibliotecas. Suponhamos um sistema de controle financeiro. Você poderia criar bibliotecas isoladas, por exemplo, de pessoa, de bancos e de estatística, que poderiam ser reaproveitadas em outros sistemas. A biblioteca consiste-se apenas de código funcional (de forma geral, uma série de funções e variáveis necessárias).
  • Criar sistemas “personalizados” também fica bem mais simples. Imagine criar um sistema inteiro para cada cliente de uma mesma atividade comercial, por exemplo. Agora, imagine se o código funcional para ambos fosse exatamente o mesmo, mas a interface completamente diferente. Isto permite que um patch de correção do programa seja o mesmo para todos os clientes, e que a interface seja única, deixando cada cliente satisfeito com sua personalização do sistema.
  • Contratar funcionários fica simplificado. Agora, seu funcionário vai trabalhar em um determinado ponto do sistema, não em um ponto que ele julgar necessário.
  • Corrigir falhas fica simplificado. Como eu falei, uma correção se aplica a todos. Testar o programa também fica mais simples, porque o código funcional é exatamente o mesmo. Erros diferentes para uma mesma ação não ocorrem mais, já que a ação sendo a mesma, desencadeará os mesmos processos internamente ao sistema. A diferença agora não está mais no programa como um todo, mas apenas na interface gráfica do mesmo. O código também está organizado. Você sabe onde está a ação, porque o local dela é exatamente no Model respectivo à ação. Não existe mais código espalhado em toda a aplicação. Tudo está em seu devido lugar.
  • Acrescentar ou remover um item na interface (por exemplo, uma opção de menu, um botão, enfim) fica extremamente mais simples. Isto porque agora a interface é apenas a interface. Recompila-se apenas a interface, atualiza-se apenas a interface. Isto reduz tempo, trabalho, tempo de upload, tempo de download, enfim, simplifica o processo drasticamente. Além de que se o item representar um novo Model, não é preciso recompilar todo o sistema, somente a interface e o novo Model…

Existe, na realidade, uma enormidade de vantagens. E o melhor: todas são inteiramente gratuitas, funcionam em todas as linguagens de programação modernas, são “implementáveis” (nada burocrático ou impossível… o maior trabalho é de se policiar para evitar que você faça coisa errada por puro vício de programação).

Vale a pena. Quem é grande já adotou. Quem é médio está adotando. Quem é pequeno também está adotando. 
E você, está esperando o que?

Engenharia de Software: métricas.

Todos nós já passamos por isto, ou iremos passar. E, sem dúvidas, vamos ficar com um enorme ponto de interrogação em cima de nossas cabeças, não importa o quão experiente sejamos.

Quanto cobrar pelo nosso sistema?

Será que devo cobrar pelo tempo que levei para montar o programa? Pelas minhas horas de trabalho? Se for, então os sistemas que levarem muitas horas podem acabar se tornando inviáveis.

E se cobrar pelo trabalho que tive para montar o sistema? Será que saberei medir corretamente o quão difícil foi para que eu montasse o sistema por completo? Não estaria me subestimando ou superestimando?

Cobrar pelo número de máquinas no cliente? Mas e se a empresa for imensa e somente usar o sistema em um único computador?

Cobrar pelo tamanho do banco de dados? Será que seria justo cobrar de uma empresa visivelmente pequena pelo enorme banco de dados que ela possui, de clientes, dependentes, ex-clientes, ex-funcionários, peças, serviços, … … …

Cobrar pelas linhas do programa? Bom, neste caso, como calcular a diferença entre um programador bem experiente, com várias técnicas de otimização e um programador iniciante, que ainda não conhece bem as “artimanhas” da linguagem?

Depois de finalmente escolher pelo que iremos cobrar, falta ainda a pergunta: QUANTO?

Seria um preço justo o valor de R$1,00 por linha de código por exemplo? Por registro no banco de dados? Por minuto de trabalho?

Pessoal, esses problemas são antigos e sempre acompanharam a evolução da nossa área. Justamente por isto que hoje, mais do que nunca, o que não falta são métricas oficializadas, bem documentadas e padronizadas, que servem de base para se calcular a complexidade do sistema e, consequentemente, o valor final do mesmo. 
Algumas delas são:

  • LOC (Lines of Code) ou Linhas de Código: Forma simples, mas que se for bem pensada pode funcionar e já vai te ajudar. Basicamente, a solução para o que falei mais acima (níveis de conhecimento da linguagem diferentes) pode ser contornada com uma prática muito adotada na CLC que é a adoção de PESOS no cálculo. Quanto maior for a experiência do programador na linguagem, maior o seu peso. No final, teremos um resultado com relativa precisão que pode servir de uma base inicial para um cálculo. É, no entanto, uma métrica muito simplista e, mesmo para empresas pequenas e iniciantes ou programadores curiosos, existem técnicas melhores…
  • FPA (Function Point Analysis) ou Análise de Pontos de Função: Uma técnica que revolucionou o mercado por um bom tempo, ajudou muito a todos mas hoje começa a apresentar certas incompatibilidades com a realidade atual. De forma geral este método é focado em I/O, sendo que o Input pode ser de várias formas (bancos de dados, arquivo, teclado, etc) e o Output também é variado (impressora, email, tela, outro programa, etc). No entanto, hoje mais do que nunca, os programas começam a evitar I/O por vários motivos e recorrem a outras técnicas mais complexas, o que deixa essa métrica problemática, principalmente em ambientes no padrão MVC (vou explicar no próximo post, aguardem).
  • UCP (Use Case Points) ou Pontos de Caso de Uso: Sinceramente, a minha favorita. Pré-requisito de se compreender a notação UML, pois você irá trabalhar com conceitos de Classe, Entidade, e outros. Através da UCP você pode saber a complexidade de cada parte do programa, medir corretamente os esforços e extimar o esforço total (e, a partir daí, o valor a ser cobrado, por exemplo).

Existem várias métricas na realidade, bem como vários programas voltados para esta tarefa. Alguns são internos às IDE’s, outros externos. De forma geral, no fundo, todos fazem o que pode facilmente ser feito manualmente, com um pouco de paciência. A vantagem é que eles automatizam a tarefa.

A partir da complexidade, eu, particularmente, defendo que se crie o número gerado como peso de cálculo. 
No meu caso eu gosto de levar em consideração o número de campos totais em uma tabela. Cálculo na seguinte regra (métrica pessoal):

  • Somatório da quantidade de células em cada tabela (linhas x colunas)
  • Ao somatório, multiplico 2 e divido todo o total por 3, arredondando sempre para CIMA.

Com os dois números em mãos, você terá o valor da complexidade do sistema e o porte do banco de dados de seu cliente. 
A partir daí use a criatividade. Cada um pode desejar fazer de alguma forma ligeiramente diferente. Um bom começo é fazer testes com a multiplicação destes fatores. 
Outra opção é criar regras do tipo 
(1 + complexidade_software) * (porte_bd / 10) + porte_bd.

Enfim, criatividade, pessoal. O importante é que vocês testem os valores e percebam se a fórmula gerou um número economicamente interessante para ambos os lados. Afinal de contas, o cliente quer pagar um preço justo e você precisa pagar suas contas. Faça um breve cálculo para saber se o valor cobrado paga ou tem a expectativa de pagar seus investimentos, seja a curto, médio ou longo prazo.

domingo, 5 de abril de 2009

Redes: o caminho para os seus dados

Seja apenas para compartilhar a Internet, seja para um complexo sistema organizacional, os computadores, mesmo domésticos, estão em grande número inseridos em uma rede.

De forma geral as redes são suas amigas, servem para lhe auxiliar na hora de trocar um arquivo com outro computador, na hora de tirar um backup, na hora de centralizar os esforços em uma empresa, na hora de acessar um recurso (por exemplo, a internet).

As redes servem para unir computadores e dispositivos compatíveis para que um acesso entre eles possa ser estabelecido. Esta é, digamos, a definição amigável de uma rede. Logicamente que tem muito mais possibilidades, a rede pode ser bem mais simples ou bem mais complexa que isto.

Não vou comentar de redes antigas como o modelo anel, coaxial. São redes que provaram ser funcionais mas que caíram em desuso porque apesar de geralmente apresentarem um custo menor, são altamente intolerante a falhas (uma falha paralisa totalmente a rede, tornando-se um meio não-confiável e difícil de se encontrar a falha). Portanto, vamos para os dispositivos usados atualmente, bem como os tipos de rede mais importantes hoje:

Dispositivos

  1. HUB: Este é, sem dúvidas, o quebra-galho de toda empresa. Se ele ainda não passou na sua vida, com certeza irá passar. São baratos, práticos e funcionam. Não maravilhosamente bem, mas funcionam, sem dúvidas. É a forma mais simples de ligar os computadores da rede. Não permite unir meios distintos (exemplo: duas redes diferentes, como a sua rede interna de seus computadores e a internet, que nada mais é que uma rede externa).
  2. SWITCH: São hubs, digamos, inteligentes. Não confundam com hub-inteligente, este é outro dispositivo que não vou citar porque dificilmente vocês vão encontrar um. Os switchs são bem mais que um mero HUB, eles são capazes de saber qual computador está em qual porta, portanto, não precisam enviar a informação para TODAS as portas, eles a envia apenas para a porta onde está o computador de destino. Isto melhora a performance da rede porque permite que várias duplas de computador conversem ao mesmo tempo (desde que as duplas possuam computadores distintos entre elas).
  3. ROTEADOR: São os TOP na linha de concentradores. Basicamente eles encontram rotas. Eles encontram o destino. Não interessa aonde ele esteja. Se ele existe, pode ser encontrado. Roteadores são extremamente inteligentes, calculam caminhos mais rápidos para os dados, permitem unir redes diferentes (outro exemplo: unir uma rede coaxial com uma rede par-trançado, esse fio azul comum hoje em dia). Alguns são repletos de recursos, como firewall, VLAN, VPN, Virtual Server, Port Forwarder, DMZ e muito mais, mas de forma geral quando mais recursos, mais caro. Se o seu roteador faz muita coisa e custa barato, provavelmente é um D-LINK, TP-Link ou similares, e este tipo de roteador somente funciona em ambiente doméstico, NUNCA coloque a sua empresa dependente de um destes…

Ambos SWITCH e ROTEADOR possuem uma importante característica, que precisa ser obedecida: Capacidade de Roteamento. Isso quer dizer que eles precisam ser capazes de enviar os dados na velocidade que sua rede requer estes dados, senão, embora a rede FUNCIONE, isto irá causar grandes “gargalos” (pontos de lentidão no tráfego dos dados).

Existem hoje, principalmente, os seguintes tipos de meio para o tráfego dos dados:

  • Cabo Par-trançado não-blindado Categoria 5: permite montar redes até 10/100/1000, mas a rede gigabit (1000) aqui se torna uma árdua tarefa e praticamente inviável. Muito comum em redes 10/100.
  • Cabo Par-trançado não-blindado Categoria 5e: permite montar redes igualmente ao Categoria 5, mas neste meio a rede Gigabit funcionará melhor, com menos problemas de performance.
  • Cabo Par-trançado não-blindado Categoria 6: permite montar redes, teoricamente, até 10 gigabits. Hardware para este tipo de rede ainda é um problema. Algumas redes gigabit funcionam no Categoria 6 por pura comodidade, já que o meio suporta melhor esta velocidade.
  • Fibra-óptica multi-modo: permite redes de até 111Gbps, mas geralmente são utilizadas entre 10 e 40Gbps, em distâncias bem interessantes (550 m). Não são caras em si, mas o equipamento ainda é BEM mais caro.
  • Fibra-óptica mono-modo: sua principal diferença é o alcance BEM superior à multi-modo, chegando a atingir até 10KM. Seu maior uso está em redes nacionais e links internacionais (exemplo: link submarino). As velocidades geralmente são as mesmas da fibra multi-modo.
  • Rádio: funciona em várias frequências, depende um pouco do tamanho da rede, da legislação do país (para não haver interferência com outras transmissões de rádio, por exemplo), dos aparelhos utilizados, enfim. São basicamente as redes Wireless, de forma geral.
  • Blootooth: Famosas por serem redes pessoais, sem fio. Funcionam bem, mas tem pequeno alcance. Ideais para um celular transmitir dados para outro celular, ou para um fone de ouvido se conectar ao celular, ou ainda para conectar o teclado ao computador.
  • 3G: Funciona relativamente parecido com um celular, é um futuro relativamente promissor. Eu particularmente não acredito muito no 3G por causa da próxima tecnologia da lista, mas SEM DÚVIDAS é um ótimo mercado e está em grande expansão.
  • Wi-max: São redes de porte metropolitano. Grandes, funcionais, rápidas, seguras. Funcionam via UHF. São de baixo-custo de implantação, requerem hardware barato, são estáveis e, repetindo, possuem longo alcance, o que melhora drasticamente o problema do wireless tradicional, que requer dezenas de access-points estratégicos para atingir uma grande área. São a solução do futuro, alguns países já começaram a implantar.

3G nem chegou ao Brasil e, em breve, acredito que já cairá em desuso por causa desta tecnologia. O grande problema é que o governo brasileiro está travando a chegada do Wi-max, mas tem um bom monivo: ele quer se assegurar que gigantes não comprem os direitos de utilização. Duas, no entanto, já comparam (se não me engano, embratel e intelig). Agora o governo quer que somente empresas menores sejam capazes de adquirir esta tecnologia, favorecendo a competição e melhorando a qualidade e os preços de internet no Brasil.

Bom, agora existem muitas formas de se implementar uma rede. 
A forma mais simples é através de uma rede em estrela (um concentrador central e os computadores se conectando à ele), utilizando-se o protocolo TCP/IPv4. Esta é a forma mais utilizada hoje em dia.

No entanto, o IPv6, já suportado por todos os sistemas operacionais modernos, é uma alternativa bem interessante, principalmente porque ele reduz drasticamente o trabalho do roteador. Resultado? O melhor de todos: maior performance. Com menos trabalho na hora de identificar a dupla DE/PARA o roteador pode encaminhar o pacote de informação muito mais rapidamente. Logicamente isto requer um roteador (ou switch) compatível IPv6.

Wireless possui, hoje, três velocidades comerciais: 54mbps, 108mbps e 300mbps. 
Não se engane, estas não são as velocidades reais, que geralmente ficam em 48mbps, 90mbps e 280mbps, quando o sinal está decentemente forte. 
Sinceramente, a única vantagem do wireless é ele ser wireless, ou seja, ele não requer cabos. De forma geral ele perde em desempenho, em segurança, em preço, em qualidade, em estabilidade. Vence em estética.

Gigabit tem seu preço. Sua maior sensibilidade à interferências e sua maior sensibilidade às curvas (em comparação à Fast Ethernet) deixa sua infraestrutura ligeiramente mais complicada. Seu hardware também é ligeiramente mais caro (um switch inteligente, com as mesmas funcionalidades, de 48 portas, custa certa de R$ 800,00 para Fast Ethernet e R$ 1500,00 para Gigabit).

Fibra também tem seu preço. Curvas são uma dor-de-cabeça e requerem um raio enorme de curvatura mínima. Também são MUITO problemáticas em emendas, que precisam ser feitas com uma pasta especial, na qual o técnico alinha as duas fibras via microscópio e as une através de nada menos que uma FUSÃO, derretendo as fibras para que a união seja perfeita.

Enfim, cada jogo tem suas regras.

Eu estou trocando a rede da empresa aqui para Gigabit. Estamos usando Cabo par-trançado categoria 5e Nexans com conectores Furukawa. Ainda preciso trocar as placas de rede dos computadores (não é caro) e preciso comprar o switch (aproximadamente R$ 1500,00). O roteador eu montei (um computador que vou comentar em outro post) totalmente personalizado, focado em possibilidade de união de várias WANs (internet) para load-balancing (distribuição da carga… funciona “COMO SE FOSSE” uma única internet bem mais rápida) e failover (se uma internet falhar eu tenho outra para evitar que tudo pare por completo). Load-Balacing e Fail-Over são uma dupla MUITO importantes no dia-a-dia de uma empresa atualmente. Principalmente quando se trabalha com WEB.

Enfim, tenham cuidado e carinho com suas redes, pois sua empresa (e talvez sua casa) depende do bom funcionamento delas. 
Sempre que forem implantar uma rede por inteiro, vale a pena procurar pela Internet nas mais novas tecnologias, meios físicos disponíveis, vantagens e desvantagens de cada uma.