Arquivo anual 21/07/2020

O que podemos esperar da tecnologia?

Já parou pra pensar o quanto a tecnologia evoluiu nessas últimas duas décadas ? Eu sou do início da década de 90 e peguei a grande parte da expansão tecnológica. Ainda sou de uma época onde se encontrava as fitas de máquina de escrever em bazares e as pesquisas eram feitas na Barsa.   Filmes eram alugados em locadora de VHS, e o orelhão estava em cada esquina. Tenho certeza de muitos que estão lendo esse texto não tem nem ideia do que são essas coisas, e se olharmos pra traz, esse passado é muito recente. O grande boom tecnológico começou nos meados dos anos 2000, onde se iniciou muito forte o conceito de globalização e as grandes empresas de tecnologias começaram a abrir mercado para o público geral. Uma década de grande evolução onde usávamos a boa e velha internet discada, lembrando que navegar de madrugada era mais barato. Época também que surgiu os incríveis pendrives e MP3s de 128mb. Hoje 20 anos depois já começamos entrar na era do compartilhamento e digitalização das informações, usando conexões de alta velocidade em equipamentos minúsculos como celulares, smartwatch’s, óculos de realidade virtual e computação em nuvem.    Se pensarmos no tempo da evolução humana, esses 20 anos passaram como segundos… Com isso, eu lanço a dúvida, o que será do nosso futuro tecnológico? Tenho certeza que cada vez mais as tecnologia estarão presente em todas as áreas, e as pessoas que não colocarem um “dedo nisso”, com toda certeza terão muita dificuldade. A tecnologia nos possibilitará avanços grandiosos na medicina, agricultura, comunicação, e até mesmo na conquista espacial, de forma que jamais imaginamos. Veremos a “internet das coisas” melhorarem muito nossas experiências com o meio em que vivemos, onde os equipamentos compartilharão informações sobre nossas preferências e nos ajudarão em diversas tarefas de nosso dia a dia. A inteligência artificial também será cada vez mais aprimorada e utilizada no meio corporativo e social. Meios de transporte inteligentes, autônomos e com energia limpa também terão um grande avanço e colheremos muitos frutos com isso. Com esses grandes avanços, temos que tomar cuidado para não regredirmos em nossas relações interpessoais e sempre lembrar que a tecnologia existe para nós ajudar a melhorar as coisas, mas não podemos jamais perder nossa essência humana. Mas com toda certeza teremos muitas conquistas nos próximos 10 anos e muitas mais nós próximos 20. Será que o pai da computação Alan Turing chegou a imaginar onde poderíamos chegar?

E você, como vê o futuro da tecnologia ?

Escopo de variáveis ADVPL

Fala pessoal, tudo bem ? Hoje tenho um assunto bem bacana pra quem trabalha com o desenvolvimento de sistemas Protheus® na linguagem ADVPL. Vamos entender melhor como funciona o escopo de variáveis e qual é o melhor para se utilizar em cada caso, isso impacta diretamente em performance e memória quando se trata de sistemas de grande escala. Primeiramente vou listar quais são os tipos de escopo e exemplificar cada um deles.

Global

Variáveis globais conseguem carregar suas informação para qualquer thread criada após a sua definição. São muito úteis quando precisamos definir ou recuperar valores em rotinas de processamento multi-thread. Devemos tomar cuidado ao utilizá-la, pois a mesma ficará disponível para qualquer execução iniciada após sua definição, podendo acarretar problemas de sobreposição caso concorra com mais de uma execução. No exemplo a seguir vamos definir duas variáveis globais que terão seus valores modificados por uma função executada em outra Thread, e na sequência recuperar seus valores na função atual.
User Function ExJobXPT()
  Local lRetJob := .F.

  // Tenta obter acesso exclusivo pra gravar a variável global
  While !( GlbLock() )
    Sleep(5)
  End While
  
  //Define e seta o valor nas variáveis globais
  PutGlbValue("lRetExec", lRetJob )
  PutGlbValue("cTexto", "Teste" )
  
  //Libera o acesso excluvivo a pilha de variáveis globais
  GlbUnlock()
  
  //Executa rotina em uma nova Thread 
  StartJob("U_ExecXPTO",GetEnvServer(),.T.)
  
  // Le os valores gravado pela função onde a váriavel global foi alterada.
  lRetJob  := GetGlbValue("lRetExec")
  If lRetJob
    Conount(GetGlbValue("cTexto"))
  Else
    Conount("Retornou Falso")
  EndIf
Return

Public

A variável Public e uma variável que fica valida em todo o escopo de execução do sistema ou seja do momento em que a mesma for criada até o momento que fizer a desconexão da sessão ativa ou destruição da mesma. É uma variável que temos que tomar cuidado ao utilizar, justamente pelo escopo abrangente que a mesma possui. A criação sem necessidade podo causar problemas de lentidão ou até mesmo problemas em tempo de execução do programa caso o mesmo não seja preparado para isso. A mesma pode ser utilizada para definir informações que serão utilizadas em diversas rotinas do sistema. Elas são equiparadas as Session’s de  outras linguagens. Alguns exemplos de variáveis públicas existentes são : cFilAnt, cEmpAnt, dDatabase, cModulo. No exemplo a seguir vamos ver um caso onde guardamos a hora inicial da chamada de uma função de menu, e verificamos se o tempo que demorou para entrar em outra função foi maior que 3 minutos.
// Função executada em um botão do menu do protheus
User Function ProcInic()
    Public cHoraIni := TIME()
    
    // Seu Código
Return


// Função executada em um outro botão do menu do protheus
User Function ProcFim()
    Local cDifTime := ElapTime ( cHoraIni, TIME() )
    If cDifTime > "00:03:00" 
        Alert("O tempo de execução entre a função inicial e final demorou mais de 3 minutos.")
    EndIf

Return

Static

As variáveis do tipo Static tem seu escopo definido dentro da execução de uma thread, ou seja, consegue ser acessado por qualquer função hierarquicamente acima ou abaixo do local onde foi declarada, normalmente as variáveis Static são declaradas logo após a definição das includes do fonte e podem ser utilizadas somente pelo programa fonte corrente. No exemplo abaixo, vamos incrementar a variável em cada nível de função chamada.
#Include "Protheus.ch"

Static nVar := 0

User Function Pai()
  nVar += 10
  conOut("Pai")
  conOut(nVar)
  Filho()
  
  // Muito importante limpar o valor da váriavel static ao concluir sua utilização
  nVar := 0
Return
 
Static Function Filho()
  nVar += 10
  conOut("Filho")
  conOut(nVar)
  Neto()
Return
 
Static Function Neto()
  nVar += 10
  conOut("Neto")
  conOut(nVar)
Return
Muito importante lembrar a necessidade de limpar a variável ao final de sua utilização, pois se as funções foram executadas novamente sem essa limpeza pode acarretar em valores errôneos.

Private

O escopo da variável Private tem sua definição valida para todas as funções hierarquicamente chamadas após a sua declaração, independente do programa fonte utilizado e a mesma se encerra ao final da execução da sua função de origem. Este tipo de escopo não necessita do identificador Private para ser criada, basta escrever o nome da variável não existente que em momento de execução o ADVPL cria como Private, isso pode ser um grande problema em caso de uma exceção, pois será muito difícil  encontrar onde a mesma foi criada. Vejo muitos analistas/programadores que não declaram as variáveis, isso além de deixar o código muito confuso pode causar problemas em tempo de execução e aumento de memória. No exemplo abaixo podemos ver que a variável cNome definida como Private dentro da função Filho() consegue ser acessada pela função Neto(), porém não consegue ser acessada pela função U_Pai().
User Function Pai()
  Filho() 
  If Type("cNome") == "C"
    conOut(cNome)
  Else
    conOut("Variável não definida")
  EndIf
Return
 
Static Function Filho()
  Private cNome := "Paulo"
  Neto()
  conOut("Filho")
  conOut(cNome)
Return
 
Static Function Neto()
  conOut("Neto")
  If Type("cNome") == "C"
    conOut(cNome)
  EndIf
Return

Local 

O escopo Local é o escopo de menor abrangência, ou seja, ele só funciona dentro da função onde a variável foi declarada, e é o escopo que devemos utilizar com mais frequência, pois terá o menor tempo de vida útil dentro da execução, consequentemente o menor custo de memória. No exemplo abaixo precisamos definir a variável local dentro da função onde queremos utilizar, note que a função Filho() não encontrará a variável cVarNome se a mesma não for declarada.
User Function Pai()
  Local cVarNome := "Paulo"
  conOut(cVarNome)
  Filho()
Return
Static Function Filho() 
  Local cVarNome := "Henrique"
  conOut(cVarNome)
Return
  
  Um detalhe muito importante do escopo de variáveis é que elas podem ser subsistidas por uma variável de escopo menor caso a mesma seja declarada dentro do local utilizado, por exemplo. Se eu possuir uma variável Public cXPTO com o valor “A” já declarado e dentro de uma novo fonte eu declarar uma variável Static cXPTO  com o valor “B” as duas variáveis existirão, mas o sistema vai priorizar o escopo mais baixo para a utilização no processamento corrente. Esta sequência hierárquica de escopo é : PublicStatic  > Private > Local .  O escopo Global não entra nessa hierarquia pois o mesmo é definido e acessado de forma diferente dos outros.   É isso pessoal, espero que ajude muito vocês e se tiveram alguma dúvida só deixar nos comentários.  

Até a próxima !!! 

 

Como se concentrar durante o período de trabalho

Para você que tem dificuldade de concentração no momento de trabalho, assim como eu, vou dar algumas dicas que vão ajudar muito na sua capacidade de concentração, criativa e cognitiva.

Veja essas dicas:

Escute uma playlist que te deixe concentrado.

No meu caso, sempre que preciso fazer tarefas onde preciso de foco total, eu coloco uma playlist de Rock que eu mesmo montei. Dessa forma tiro totalmente o som externo, as conversas  e distrações que tiram meu foco.

Pode ser o tipo de música que você preferir, no meu caso foi o bom e velho Rock And Roll .

Vou deixar minha playlist do Spotify aqui caso alguém queira fazer as “Pedras rolarem”.

Open in Spotify

Defina uma agenda em sua rotina.

Uma dica muito importante, para você que acaba se perdendo no tempo, ou se aguem te chama a todo momento, é utilizar uma agenda para organizar suas tarefas.
Pode ser um agenda de papel (raiz) ou algo mais moderno como utilizar a agenda do Google Calendar ou qualquer agenda virtual, o importante é se organizar.

Organize suas tarefas e processos.

Tenha uma forma de organizar a ordem das suas tarefas, assim você não esquece de nenhuma e vai ter uma produtividade muito maior.

Existem diversas ferramentas e metodologias para isso.

Uma metodologia muito útil para isso é o Scrum que foi desenvolvido para gerenciar projetos, organizar tarefas e agilizar processos. Para mim ele é muito mais que uma ferramenta de trabalho e pode ser empregado em todas as áreas da sua vida.

Uma ferramenta bem bacana que uso para organizar minhas tarefas é o Trello. Essa ferramenta te ajuda a organizar suas tarefas em card’s e dividi-las em etapas de processo.

Faça pausas durante o trabalho.

É muito importante fazer pausas durante o expediente. Nenhuma mente é produtiva 100% do tempo, e sem as pausas nossa mente e nosso corpo pode chegar a uma exaustão e comprometer a qualidade do seu trabalho.

Então, faça pausa para tomar um café, distrair a cabeça ou até mesmo bater um papo com algum colega de trabalho.

É isso mesmo, as vezes desviar o foco te ajuda a ter foco no momento correto !!!

 

Essas são as minhas dicas para que seu trabalho seja mais produtivo e com uma melhor qualidade.

Script para reorganizar/recriar índices no Microsoft SQL Server

Muitas vezes sentimos uma performance terrível em nosso banco de dados.

Um dos fatores que pode fazer isso acontecer é a defasagem dos índices das tabelas de nosso banco.

Isso acontece devido a  grande quantidade de manipulações dos dados, principalmente com os comandos Insert e Delete.

Para isso podemos criar um script para reorganizar, e dependendo dos casos recriar os índices do nosso SQL Server…
Essas ações melhoram o desempenho do banco.

Vou explicar os passos para montar esse Script que vai te ajudar muito.

Primeiramente, vamos criar algumas variáveis de controle que serão utilizadas no momento da leitura dos índices…

DECLARE @tableName nvarchar(500) 
DECLARE @indexName nvarchar(500) 
DECLARE @percentFragment decimal(11,2)
DECLARE @page_count int

 

Na sequência vamos definir nosso Cursor, que servirá para armazenar a lista de índices que iremos realizar a manutenção.

Dentro da criação do cursor, escrevemos um comando Select que vai cruzar dados entre a tabela de status dos índices (sys.dm_db_index_physical_stats), a tebela de tabelas(sys.tables), a tabela de Schemas(sys.schemas) e a tabela de Índices(sys.indexes).

Definimos um parâmetro de busca de fragmentação onde o % de fragmentação for maior que 5% e a quantidade de páginas do índice for maior que 10.

Com isso começamos a pegar os índices que já começam a apresentar lentidão nas consultas…

DECLARE FragmentedTableList cursor for 
SELECT  dbtables.[name] AS 'Table',
    dbindexes.[name] AS 'Index',
    indexstats.avg_fragmentation_in_percent,
    indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables 
  ON dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas 
  ON dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes dbindexes 
  ON dbindexes.[object_id] = indexstats.[object_id]
  AND indexstats.index_id = dbindexes.index_id
  AND dbindexes.[name] IS NOT NULL
WHERE indexstats.database_id = DB_ID()
    AND indexstats.avg_fragmentation_in_percent > 05
    AND indexstats.page_count  > 10 
ORDER BY indexstats.page_count DESC, indexstats.avg_fragmentation_in_percent DESC
 
OPEN FragmentedTableList

 

Por último, vamos abri o cursor, fazer a leitura dos índices e executar as devidas manutenção:

Quando o percentual de fragmentação estiver entre 5% e 30%, vamos realizar o reorganize do índice, ou seja, vamos reorganizar este índice.

Agora, se o percentual for maior que 30% vamos realizar o rebuild do índice, ou seja, realizar a reconstrução do mesmo, pois a defasagem do mesmo já esta bem critica.

FETCH NEXT FROM FragmentedTableList  
INTO @tableName, @indexName, @percentFragment, @page_count
 
WHILE @@FETCH_STATUS = 0 
  BEGIN 
    PRINT 'Processando ' + @indexName + ' na tabela ' + @tableName + ' com ' + CAST(@percentFragment AS NVARCHAR(50)) + '% fragmentado' 
       
    IF(@percentFragment BETWEEN 05 AND 30) 
      BEGIN 
        
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REORGANIZE;') 
        PRINT 'Concluindo a reorganização do índice ' + @indexName + ' da tabela ' + @tableName 
      END 
    ELSE IF (@percentFragment > 30)
      BEGIN 
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REBUILD; ') 
        PRINT 'Concluindo a recriação do índice ' + @indexName + 'da tabela ' + @tableName 
    END  
    FETCH NEXT FROM FragmentedTableList  
    INTO @tableName, @indexName, @percentFragment,@page_count
  END 
CLOSE FragmentedTableList 
DEALLOCATE FragmentedTableList

 

Agora vejam o exemplo completo do nosso script:

DECLARE @tableName nvarchar(500) 
DECLARE @indexName nvarchar(500) 
DECLARE @percentFragment decimal(11,2) 
DECLARE @page_count int
 
DECLARE FragmentedTableList cursor for 
SELECT  dbtables.[name] AS 'Table',
    dbindexes.[name] AS 'Index',
    indexstats.avg_fragmentation_in_percent,
    indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables 
  ON dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas 
  ON dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes dbindexes 
  ON dbindexes.[object_id] = indexstats.[object_id]
  AND indexstats.index_id = dbindexes.index_id
  AND dbindexes.[name] IS NOT NULL
WHERE indexstats.database_id = DB_ID()
    AND indexstats.avg_fragmentation_in_percent > 05
    AND indexstats.page_count  > 10 
ORDER BY indexstats.page_count DESC, indexstats.avg_fragmentation_in_percent DESC
 
OPEN FragmentedTableList 
FETCH NEXT FROM FragmentedTableList  
INTO @tableName, @indexName, @percentFragment, @page_count
 
WHILE @@FETCH_STATUS = 0 
  BEGIN 
    PRINT 'Processando ' + @indexName + ' na tabela ' + @tableName + ' com ' + CAST(@percentFragment AS NVARCHAR(50)) + '% fragmentado' 
       
    IF(@percentFragment BETWEEN 05 AND 30) 
      BEGIN 
        
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REORGANIZE;') 
        PRINT 'Concluindo a reorganização do índice ' + @indexName + ' da tabela ' + @tableName 
      END 
    ELSE IF (@percentFragment > 30)
      BEGIN 
        EXEC( 'ALTER INDEX ' +  @indexName + ' ON ' + @tableName + ' REBUILD; ') 
        PRINT 'Concluindo a recriação do índice ' + @indexName + 'da tabela ' + @tableName 
    END  
    FETCH NEXT FROM FragmentedTableList  
    INTO @tableName, @indexName, @percentFragment,@page_count
  END 
CLOSE FragmentedTableList 
DEALLOCATE FragmentedTableList

 

Agora o mesmo pode ser executado periodicamente, ajudando a melhorar a performance do banco de dados.

Espero que gostem!!!

Até a próxima !!!