Utilizando Exit para retorno da função

Tradicionalmente o Delphi possui a possibilidade de retornar o valor da função através do próprio nome da função, ou através da variável “Result”.

Porém, umas das novidades que saiu no Delphi 2009, mas que poucas pessoas hoje conhecem (ou pelo menos comentam), é a capacidade de retornar o valor de uma função através do comando “Exit”.

Isso é útil quando você precisa, depois de alimentar o retorno da função, chamar Exit para sair do escopo atual:

O exemplo abaixo (apenas educativo!):

Pode ser simplificado assim:

Até a próxima!

 

Paradigma da Programação Orientada à Objetos (POO)

Quando comecei com programação, lá no anos 90, o paradigma da orientação à objetos já era algo muito discutido. Ele foi criado na década de 60 (para saber um pouco da história, acesse http://www.webgoal.com.br/origem-da-orientacao-a-objetos) , mas vejo que até hoje as pessoas tem dúvidas, se questionam a respeito e algumas vezes vão contra ele. Existe a legião de pessoas que idolatram a orientação à objetos, e vejo recentemente uma grande tendência contra ela, que vem crescendo à cada dia. Não sei o que o futuro nos aguarda, mas pode ser que venhamos à condená-la. Assim são as coisas com a evolução. O que posso dizer, humildemente, é que eu a adoro.

A orientação à objetos tem uma característica que considero fantástica: a forma que ela consegue organizar as coisas.

Durante anos estudei programação e análise de sistemas e, no início, mas durante um período que durou alguns anos, me questionava muito se eu realmente entendia sobre orientação à objetos. Entendia de classes, de herança, de polimorfismo, de sobrecarga de métodos e todas as outras coisas relacionadas, mas não era capaz de responder à simples questão: porque as pessoas precisam disso se conseguem desenvolver sistemas sem seguir a orientação à objetos? Não pode ser simplesmente pela reutilização do código, porque uma função também pode ser reutilizada. Porque criar uma estrutura se posso ir diretamente ao ponto e resolver o problema? Felizmente, a resposta para essa pergunta me apareceu futuramente.

Somente quando comecei a trabalhar com grandes projetos, o que aconteceu depois que entrei na faculdade (sim, comecei a desenvolver muito antes disso) é que fui entender a importância da facilidade de manutenção e de comunicação com outras pessoas da equipe, referente ao código-fonte.

A grande maravilha da orientação à objetos para mim não é relacionado aos seus pilares: abstração, encapsulamento, polimorfismo e herança (não despreso esses recursos!). É a forma como ela organiza as informações que é mágico. Você pode ter milhões de arquivos no seu computador, e todos vão funcionar e você eventualmente vai encontrar todos sempre que possível, mas mesmo assim, você os organiza em pastas, não é? Por que? Porque dessa forma, fica muita mais fácil trabalhar com eles. É a mesma coisa! Ah, mas eu poderia utilizar namespaces para organizar meu código… sim, você poderia! Eu utilizo os dois (classes e namespaces), e sou feliz assim! Quer utilizar namespaces apenas, e classificar suas funções? Vai em frente! Porque não importa o que você faça, o importante é que dê certo! Não existe certo ou errado em informática, desde que  as pessoas consigam aquilo que elas busquem.

Muitos argumentam que OO não é performático. Comparado a que? Procedural? Sim, pode ser verdade. E daí? Ah, então não devemos utilizar OO para nenhum projeto? Responda-me uma coisa: quando as pessoas vão para o fundo do mar, elas vão de submarino ou de avião? Mas o avião não é mais veloz (é, forcei um pouco no exemplo!)?  O que quero dizer é que não existe uma tecnologia que resolve todos os problemas. Cada coisa tem seu papel. Se vou realizar um processamento em lote, provavelmente farei sem utilizar OO, para que tenha o máximo de performance. Provavelmente farei tudo da forma mais direta possível, porque o problema exige isso. Mas, se ao mesmo tempo, tiver um deadline muito curto e já exista uma classe preparada para o serviço, só que utiliza ORM, etc, etc, etc, talvez utilize a OO simplesmente porque tenho que entregar o projeto, e sem isso, não conseguiria atingir o prazo. É melhor meia vitória do que nenhuma. Por outro lado, prefiro utilizar OO sempre que possível, porque isso me dá um egrenciamento do código que eu preciso nas manutenções, que é essencial para o desenvolvedor. Outras formas de desenvolver sistemas podem gerar uma melhor performance do programa, mas e quanto à performance da equipe? Isso também importa.

As dificuldades em desenvolvimento de sistemas são relacionadas à prazos, regras de negócios, relacionamento com os clientes, processos internos dentro da fábrica de software. A tecnologia é só a forma de chegar lá, é o veículo para atingir os objetivos. É como ter que ir para outra cidade, podendo escolher ir de carro, ônibus ou avião. Mas o problema real ainda é ir para outra cidade. O que geralmente vejo são as pessoas discutindo que é melhor ir de carro, outros de avião. Poucos discutem sobre: por que preciso ir para outra cidade? O que vou fazer lá? Essas são as questões, porque sem isso, nada adianta qual veículo você vai usar.

Costumo falar que informática é igual time de futebol. Fulano torce para aquela tecnologia, siclano para aquela linguagem de programação específica. Isso só demonstra imaturidade profissional. O bom profissional sabe que essas coisas são passageiras e que o importante é resolver o problema, seja como for. É a satisfação do cliente que importa, e ele não está preocupado com isso. Os envolvidos nos projetos geralmente não se preocupam com a tecnologia. Os pedidos estão caindo? Minha empresa está faturando? Como estão as vendas? Está formando filas nos caixas? Nada disso tem a ver com tecnologia. Isso tem a ver com pessoas. Foco nas pessoas. A tecnologia é o veículo para a resolução dos problemas. Se o faturamento está ótimo, importa se foi feito utilizando POO ou da forma procedural? Claro que não! Importa que funciona. E pode ter certeza que dá para se fazer bem feito das duas maneiras, ou de qualquer outra.

Outra vantagem de se utilizar OO que me ajuda muito, é algo que obtenho também dos padrões de projeto. Facilidade de comunicação com a equipe. Quando as pessoas estão integradas com o código, é fácil simplesmente dizer: utilize esse ou aquele objeto para resolver isso. Faça tal sobrecarga, etc, etc. É simplesmente fácil de se comunicar, porque os objetos são abstrações das estruturas e dos comportamentos, e quando falamos de comportamento, estamos utilizando uma linguagem comum a todos.

Se sua equipe está acostumado com a forma procedural, não mude! Não tire o know-how de como ter sucesso (a não ser que você não esteja tendo)! Se sua equipe está acostumada à OO, não mude! Não tire o know-how dela. Mudar os processos internos é traumatico e retira o conhecimento daqueles que já o detém. Cade equipe precisa encontrar a própria forma de trabalhar. Eu encontrei a minha. Espero que você também encontre a sua.

Mapped File (ou Arquivos Mapeados na Memória)

Foi por acaso que descobri como trabalhar com arquivos mapeados na mémoria (mapped files). Estava lidando com um projeto onde gostaria de trocar informações com os registradores de desenpenho do monitor de performance do Windows (Perfmon) e o exemplo que encontrei fazia o uso desse mecanismo para trocar informações entre a DLL que seria utilizada pelo Perfmon e o software que seria monitorado.

Para aqueles não acostumados com o termo, arquivos mapeados na memória (ou geralmente conhecidos como mapped files) são respresentações de arquivos que existem diretamente na memória, e podem ou não existir no disco, ou seja, você consegue escrever e ler informações diretamente na memória como se o estivesse fazendo em um arquivo no disco rígido.

Isso geralmente é utilizado para integrar dois processos diferentes, visto que a memória passa a ser um ponto de contato entre os dois processos. Foi exatamente essa a razão para utilizar no exemplo do Perfmon. Contudo, existem várias outras razões que justifiquem esse uso, seja por performance (afinal, acesso ao disco nunca foi o melhor amigo da performance) quanto, por exemplo, evitar problemas com direitos de acesso em disco, nos casos onde a informações será gerada de forma temporária. Cada caso ditará a necessidade ou não desse recurso.

A primeira coisa a saber, é que todos os processos que utilizarão esse “arquivo” na memória devem referencia-lo pelo mesmo nome. Isso é que irá determinar que estão lidando com o mesmo espaço de memória.

Para nos utilizarmos disso, a primeira coisa a ser feita é conhecer as instruções responsáveis pela manipulação da memória. Saiba que o Delphi utiliza-se para isso a própria API do Windows, então quem quiser qualquer referência precisa procurar no próprio site da Microsoft (http://msdn.microsoft.com/pt-br/).

CreateFileMapping (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537(v=vs.85).aspx)


A função CreateFileMapping é a responsável por criar ou abrir (caso um arquivo físico seja informado) o arquivo na memória – afinal, é exatamente isso que queremos fazer, não é?.

Ela possui 6 parâmetros de entrada e uma saída:

  • hFile – Handle do arquivo, se ele já existir. 0 se você quer criar um novo.
  • lpAttributes – Estamos falando de arquivos, certo? Os atributos aqui, são os atributos de arquivos (ReadOnly, Hidden, etc. https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx)
  • flProtect – Forma de proteção da memória que iremos utilizar. Fique atento que nem todas as formas de proteção estão disponíveis para serem utilizadas com a função CreateFileMapping. Você pode encontrar quais poderão ser utilizadas e quais não, diretamente em https://msdn.microsoft.com/pt-br/library/windows/desktop/aa366786(v=vs.85).aspx
  • dwMaximumSizeHigh e dwMaximumSizeLow – Relacionam-se aos tamanhos máximos do arquivo dentro da memória.
  • lpName – Nome de referência do arquivo que utilizaremos para identificá-lo.
  • Result – O retorno da função será o handle do arquivo na memória.

É possível ainda, quando sabemos que o arquivo já existe, de utilizar a função OpenFileMapping (https://msdn.microsoft.com/pt-br/library/windows/desktop/aa366791(v=vs.85).aspx).

É importante adicionar que a função CreateFileMapping, caso tenha algum problema, grava as informações de erros que poderão ser utilizadas posteriormente através da função do RaiseLastOSError (http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.SysUtils.RaiseLastOSError), que utilizaremos para identificar se a criação ocorreu normalmente ou não.

Obs: Após a criação do arquivo, é necessário chamar a função CloseHandle, que irá liberar o handle.


MapViewOfFile (https://msdn.microsoft.com/pt-br/library/windows/desktop/aa366761(v=vs.85).aspx)

Uma vez que já criamos o arquivo na memória, devemos fazer a chamada da MapViewOfFile para podermos manipular o conteúdo desse arquivo. Existe uma diferença importante quando se usa a MapViewOfFile. Quando chamamos a CreateFileMapping, estamos “alocando” aquela quantidade de memória, mas não necessariamente faremos o uso daquela mesma quantidade quando formos utilizá-la. Assim, a função MapViewOfFile determina a “porção” daquela memória alocada que iremos utilizar, ou seja, qual será o espaço dentro daquela memória, que iremos utilizar (mais em https://stackoverflow.com/questions/32299112/mapviewoffile-offset-how-to-use-it).

Ela possui 5 parâmetros de entrada:

  • hFileMappingObject – O handle do arquivo (aquele mesmo retornado pela CreateFileMapping).
  • dwDesiredAccess – O tipo de acesso ao arquivo mapeado (verificar o link da função para identificar os tipos possíveis)
  • dwFileOffsetHighdwFileOffsetLow – É a janela do offset, que determina o ponto de início do espaço de utilização da memória.
  • dwNumberOfBytesToMap – O número de bytes a ser mapeados.
  • Result – O retorno da função é o endereço da memória de início do mapeamento.

Mais em: https://stackoverflow.com/questions/9889557/mapping-large-files-using-mapviewoffile

Aqui também precisaremos fazer o uso da função RaiseLastOSError para identificarmos se tudo ocorreu bem.

Obs: Após a criação do mapeamento, é necessário chamar a função UnmapViewOfFile para liberar o mapeamento.

Basicamente isso é o necessário. Vamos ver um exemplo:

Gravação da informação na memória

Esse é o programa que irá gravar as informações na memória. É um formulário simples com um botão na tela, que grava as informações na memória conforme ele é clicado. Preste atenção apenas que o arquivo é criado no FormCreate e destruído no FormDestroy, porque, de outra forma, ao clicar no botão o arquivo seria criado e destruído muito rápido, não dando tempo para a aplicação que irá ler o conteúdo obter o valor correto. Veja que ele faz uso das funcões àcima descritas. Ele tende a ser autoexplicativo.


Leitura da informação da memória

Perceba que ele faz uso da função OpenFileMapping para a leitura. Basicamente, acessa o arquivo mapeado na memória e pega o seu conteúdo. Muito simples. 🙂

Download do código fonte do exemplo: Aqui

TryStrToInt (Conversão de tipos de dados)

A SysUtils é algo que sempre me surpreende. Confesso que não conhecia a função TryStrToInt (iremos falar mais sobre ela abaixo) mesmo durante longos anos de desenvolvimento. Talvez isso tenha sido uma das minhas maiores falhas, mas aprender sempre é algo que me satisfaz muito. Lendo um livro do Nick Hodges, ele comentou sobre formas erradas de validação da conversão de números inteiros, para exemplificar a maneira como as pessoas utilização exceções (try…except) de formas erradas, e lá estava eu, nú sobre a análise perspicaz de um dos maiores nomes do mundo delphi (ele é diretor de gerenciamento de produtos da Embarcadero Technologies). Depois de me recompor, fui aprender mais sobre o assunto.

A função TryStrToInt é muito simples. O seu retorno é um boolean, que indica se a conversão é possível. Ela recebe como primeiro parâmetro a string que será verificada. Como segundo parâmetro, você deve passar uma variável (é um parâmetro de saída/out) que armazenará o número inteiro possível da conversão (entenderemos melhor isso).

Abaixo encontra-se um pequeno exemplo:

Existem duas strings que serão convertidas: NumeroValido e NumeroInvalido.

Número válido possui uma string válida para conversão para inteiros: 12345

Número inválildo possui uma string inválida para a conversão para inteiros: 98765A321 (perceba a letra A no meio da string).

Quando utilizo a string válida, a função TryStrToInt retorna True, e False para a string inválida.

O segundo parâmetro, que chamei de Retorno (porque trata-se de um parâmetro de saída/out), para a string válida, é a própria string convertida, ou seja, é o número inteiro 12345. Na segunda tentativa, quando utilizamos a string inválida, a variável Retorno possui o valor 98765, ou seja, o número convertido até onde foi possível, que foi até o momento que não se encontrou um número inválido, descartando-se o restante, à partir daí.

Copie o código àcima e tente em seu ambiente, para que tudo fique mais claro.

Olhando internamente a codificação do TryStrToInt, é possível perceber que ele faz uso de uma antiga função chamada Val (engraçado, essa função estava perdida em algum lugar da minha mente, pois me lembro dela, embora nunca a tivesse utilizado) que serve para conversão de string em números.

Vale lembrar que junto com a TryStrToInt, existem várias outras funções para outros diferentes tipos de dados (TryStrToBool, TryStrToFloat, TryStrToCurr, etc) que poderão ser utilizados, dependendo da situação.

Try…except nunca mais (calma, apenas para conversão safety-mode de strings!)

Trava dos controles do formulário (Lock Controls)

Estive pesquisando alguns recursos do Delphi ultimamente e me deparei com um que, deixando a simplicidade de lado, é de grande utilidade. Várias e várias vezes, no momento da codificação, o meu foco era simplesmente a manutenção de uma lógica no arquivo “.pas”, mas como o Delphi abre o formulario (.dfm) automaticamente muitas vezes, acabamos por influenciar o layout deles por acidente. O típico caso é quando precisamos alterar apenas uma propriedade do componete visual e acabamos por desalinhá-lo com os demais componentes. Nada muito sério, mas sempre uma cheteação.

Para facilitar a vida do desenvolvedor, o Delphi possui o recurso de travar os componentes do formulário. Basta ir em “Menu -> Edit -> Lock Controls” que os componentes do formulário (visuais e não visuais) ficarão travados, ou seja, não poderão ser movimentados dentro do formulário.

 

Breakpoint condicional na hora de debugar

Qual desenvolvedor não se encontrou criando uma variável de controle, para armazenar o valor atual do contador, apenas para, conforme condição que verificasse o valor do contador, entrar em um breakpoint? Isso porque, dentro de um loop, as 1000 primeiras vezes que ele passava por ali não era interessante. Assim, o breakpoint executaria apenas quando a condição fosse satisfeita. Mas isso implica alterar o código-fonte para obter esse benefício.

Pouco gente sabe, mas o Rad Studio, assim como outras softwares, possuem a possibilidade de adicionar um breakpoint, sendo que sua execução fica condicionada a uma determinada situação. Isso sem qualquer alteração do código-fonte, pois funciona como um recurso próprio.

Vamos imaginar um loop que seja executado, aproximadamente, 10.000 vezes. Pode ser que o desenvolvedor queira debugar o funcionamento do comando contido no loop apenas na milésima e primeira vez, ou seja, apenas quando o contador for = 1000  (começou no zero!).

Clickando-se com o botão direito do mouse na posição do breakpoint, voce encontrará a opção “Breakpoint Propertires” (Propriedades do breakpoint).

Elá abrirá uma janela com algumas opções e informações interessantes. A que estamos interessado no momento é a Condition. O breakpoint apenas funcionará quando satisfizer a condição informada ali. Da forma como está abaixo, apenas quando I possuir o valor de 1000, é que o breakpoint será parará a execução.

Espero que isso tenha sido útil à você. Embora muito simples, vejo que poucas pessoas conhecem e utilizam esse recurso.

Agradecimento ao Guilherme Chiarini, pela dica.

Problemas na conexão com Dephi e Oracle em máquinas 64bits

Se você está tendo problemas em conectar sua aplicação Delphi em um banco de dados Oracle, e você utiliza uma máquina 64bits, não se preocupe. O problema é chato de diagnosticar, mas a solução é simples, embora trabalhosa. Provavelmente, na instalação do Delphi (ou RAD Studio), você, assim como eu, instalou-o na pasta padrão para aplicativos de 32bits (x86), ou seja:

Após muito pesquisar, descobrí que o problema ocorre porque o “Client” do Oracle não conecta através de pastas com alguns tipos de caracteres, entre eles o parênteses “(” e “)”. Tanto que se você gerar um executável e colocá-lo no seu desktop, por exemplo, ele irá conectar normalmente. Por isso, o fato de sua máquina ser 64bits não interfere na conexão, mas sim o caminho de onde a conexão será chamada. Só nos resta agora a solução, que será reinstalar o Delphi (RAD Studio) em outro caminho, como por exemplo, “C:\Arquivos de Programas” ou mesmo “C:\Delphi”, para podermos então testar a conexão em tempo de “Design”.

Gerador de documentação do RAD Studio

Uma das coisas mais interessantes nas novas versões do RAD Studio e que, pelo que vejo, ainda não é explorado adequadamente pelos desenvolvedores, é o adorável gerador de documentação. Muitos já o conhecem, ou mesmo já ouviram falar, mas poucos exploram efetivamente seus recursos. A documentação do software é um dos tesouros mais sagrados de uma empresa, visto que provê comunicação entre os diversos setores da organização. Facilita o entendimento entre Analistas, Arquitetos, Programadores, Gerentes, Estagiários e qualquer outro interessado. Garante a agilidade dos processos internos, pois facilita o entendimento e transmite segurança aos profissionais, que na maioria das vezes, estão em ambientes que exigem uma atuação sobre-humana. É, além de tudo e principalmente, elemento de grande importância na diminuição dos riscos nas análises das empresas, pois garante que o conhecimento será perpetuado em caso de problemas.

O que é fantástico é que o RAD Studio nos fornece a documentação praticamente pronta. Só com as informações geradas, sem que nada seja feito, já é possível possuir uma rica fonte de informação sobre o software.

Abaixo encontra-se um exemplo de documentação gerada pelo RAD Studio:

Caso não esteja familiarizado com o gerador de documentação e queira dar uma olhadinha, basta habilitar o suporte a modelagem em seu projeto (Project->Modeling Support) . Com o suporte a modelagem habilitado, você será capaz de visualizar a modelagem (View-> Model View) e gerar a documentação a partir dela, clicando com o botão direito do mouse e depois em “Generate Documentation”. Os passos a seguir são auto-explicativos.

Mas é possível ir além, e incluir suas próprias informações na documentação, deixando-a ainda mais poderosa, e adequando-a à sua organização, de uma maneira incrivelmente fácil. Todos conhecem os comentários padrão do Delphi:

Esses comentários, embora úteis na geração de informações aos desenvolvedores, não são exportados juntos na documentação gerada, não integrando a documentação final do sistema. Mas há a possibilidade de inserirmos um comentário de barra tripla, conforme abaixo:

Comentários de barras triplas tem a característica de serem gerados juntos com a documentação. Isso nos dá a possibilidade de aprimorá-la com informações e características que sejam relevantes à nossa organização, tornando-a ainda mais rica e interessante. Outro elemento que é importante ser mencionado é que a documentação categoriza-se pela utilização de TAGS, que no final serão vistas como títulos. Vejamos uma classe pessoa sendo documentada. Supomos que eu queira criar um tópico com a descrição completa da classe, a nível organizacional, coisa que o gerador de doumentação não realizará sozinho. Eu teria algo parecido a:

Repare que criamos a documentação logo a cima da classe TPessoa. Isso irá caracterizar que a documentação é referente à classe TPessoa. Outro ponto a se notar é a utilização da TAG , que limita o escopo da documentação. Antes de visualizarmos o resultado disso na documentação final, vamos documentar os métodos Andar e Falar, mostrando como é possível criar uma documentação detalhada da classe:

Perceba que os métodos estão documentados da mesma forma, com os comentários de barras triplas logo a cima de suas declarações. Utilizei a mesma TAG de , mas poderia ser utilizada qualquer outra TAG. O resultado disso é o que temos a seguir:

Repare como nossa documentação passou a fazer parte da documentação gerada pelo RAD Studio. Ao analisarmos os métodos individualmente, veríamos que o mesmo ocorreu com eles.

Você pode estar pensando que tudo isso é bem legal, mas que como agora todo essa documentação está lá no código, a visualização do código em sí tornou-se algo muito difícil, visto que agora ela está “sujando” todo o texto do editor. De fato é verdade, e antes um software mal documentado do que um ilegível. Mas graças aos nossos amigos da Embarcadero, podemos utilizar o recurso das “Regions” que “esconderá” toda área indesejada para nós.

Para a criação de uma region, basta:

Repare que o editor adicionou o sinal de + e -, onde você agora pode expandir ou diminuir o conteúdo dentro de uma region. Aplicando isso à nossa documentação, teríamos o seguinte:

Dessa forma você consegue documentar facilmente seu sistema e ainda torná-la elegante dentro do código.