Dicas sobre desenvolvimento de software, gestão e tributações

Rede Social

15 de dezembro de 2020

UML: O que é e como funciona


 Unified Modeling Language é uma linguagem de notação muito utilizada em projetos de desenvolvimento de softwares, mas seu uso não se resume apenas a software, ela pode ser usada para muitos tipos de planejamentos e projetos.

Ela é construída através de diagramas que são compostos por elementos gráficos relacionados entre si e com pequenos textos que os descrevem.

Existem vários tipos de diagrama e vou mostrar os mais utilizados abaixo:

Diagrama de casos de uso
O caso de uso documenta o que o sistema faz do ponto de vista do usuário. Esse é o mais conhecido e o que mais se aplica a diversas situações não apenas a desenvolvimento de software.
Ele possui:
- Atores (usuários, equipamentos ou sistemas interligados)
- Casos de uso (as funcionalidades do sistema)
- Comunicação (o que liga o usuário com a funcionalidade realizando uma ação)

Diagrama de caso de uso – Wikipédia, a enciclopédia livre


Diagrama de classe
O diagrama de classes serve para mostrar a estrutura da aplicação, muitas vezes utilizado para planejamento do banco de dados, ou seja este é específico para desenvolvimento de software.

Modelos e Exemplos de Diagrama de Classe Online | Creately


Diagrama de sequência
Diagrama de sequencia mostra a sequencia de ações que um usuário pode fazer (lembre que usuário pode ser uma pessoa, outro sistema, um equipamento etc.)

Ele vai ter um usuário, os elementos gráficos que representam cada etapa e as setas que indicam uma ação seja do usuário (seta para frente) ou da etapa requisitando uma ação do usuário (seta para trás)

 

Diagrama de Atividades
O diagrama de atividades serve para ilustrar as ações que podem ser tomadas na aplicação, juntamente com suas condições e consequências.

UML - Diagrama de Atividades - Purainfo


Ferramentas para UML
ArgoUML http://argouml.tigris.org/
Astah http://astah.net/editions/community
Draw http://draw.io não é focada em UML

Ler

8 de dezembro de 2020

SQL Server: Como saber os últimos comandos executados


 SQL Server Express - Backup, Recursos, Comparando edições

No post de hoje irei mostrar uma forma simples de verificar quais foram os últimos comandos executados no SQL Server, detalhe que são para comandos que ainda estão em chache do SQL não para qualquer comando de qualquer data.

SELECT TAB.TEXT
FROM SYS.DM_EXEC_CACHED_PLANS AS PLANS
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(PLANS.PLAN_HANDLE) AS TAB


Com esse comando são exibidos os comandos no cache, aqui vale bastante colocar cláusulas where pois muitas vezes são exibidos comandos internos do que o SQL server executa então vamos à um exemplo.


SELECT TAB.TEXT
FROM SYS.DM_EXEC_CACHED_PLANS AS PLANS
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(PLANS.PLAN_HANDLE) AS TAB
WHERE TAB.TEXT LIKE '%UM TEXTO DO MEU COMANDO%'

Com um where junto a um like podemos procurar parte do que está escrito no comando.

Ler

17 de novembro de 2020

SQL: Converter tempo decimal em horas e minutos





No post de hoje irei mostrar algumas formas de transformar horas em decimal, no meu caso essa necessidade surgiu porque a funcionalidade grava as horas de uma tarefa no formato decimal, pois o usuário desejava ver essa quantidade de tempo em decimal e também realizar alguns cálculos, mas depois de certo tempo ele quis também um relatório onde exibisse a quantidade de tempo no formato de horas (time)

A primeira forma que vou mostrar é para converter para varchar, isso porque o período de tempo poderia ultrapassar as 24 horas que o formato time do sql suporta

DECLARE @HORAS decimal(7,4) = 25.5599
SELECT
RIGHT('0' + CAST (FLOOR(@HORAS ) AS VARCHAR), 2) + ':' +
RIGHT('0' + CAST(FLOOR((((@HORAS * 3600) % 3600) / 60)) AS VARCHAR), 2) + ':' +
RIGHT('0' + CAST (FLOOR((@HORAS * 3600) % 60) AS VARCHAR), 2)

Caso não ocorra nunca a possibilidade de passar das 24 horas você pode converter para o formato time de uma forma mais simples.

DECLARE @HORAS decimal(7,4) = 20.5599
SELECT  CAST(CONVERT(VARCHAR,DATEADD(SECOND, @HORAS * 3600, 0),108) AS TIME)

Ler

27 de outubro de 2020

Python: List Slices


 Como executar seu código python diretamente no Sublime-Text | by Willyan  Guimarães | experienceCode | Medium

No post de hoje vamos ver uma forma bem interessante e que facilita bastante para se obter valores de listas.
Imagine que temos uma lista de ints conforme a lista abaixo.

list = [0, 1, 5, 8, 14, 27, 31, 45, 63, 76]

E eu quero imprimir na tela os valores das posições 2 até a 5, normalmente pensaríamos em um loop como um for, mas em Python temos uma forma bem simples de resolver isso.

print(list[2:6])

Com esse comando o retorno seria:

[5, 8, 14, 27]

Ou seja os ints nas posições 2 (não se esqueça que a contagem começa do zero), até a posição 5 (a posição 6 não é selecionada por mais que se tenha colocado 6 no comando).

Também podemos omitir um dos dois parâmetros, seja o primeiro que é o número inicial ou o segundo que é o número final
Se eu executar o comando:

print(list[:5])

Seria a mesma coisa que executar o comando print(list[0:5]).

E se executar
print(list[7:])

Ele vai imprimir à partir da posição 7 até o final da lista.

List slices também pode ser usado com um terceiro parâmetro que serve para indicar a quantidade de posições à percorrer de cada vez, como por exemplo:

print(list[2:9:2])

O resultado irá imprimir à partir da posição 2 até a posição 9 de dois em dois como o abaixo:

[5, 14, 31, 63]

 

Também temos a opção de colocar um número negativo no terceiro parâmetro, isso faz com que a lista seja retornada ao contrário como por exemplo:

 print(list[7:4:-1])

Retorno:

[45, 31, 27]

Ler

15 de outubro de 2020

Python: Uma função Pythônica para validar CNPJ



Seguindo a ideia do post anterior, onde mostrei uma solução para a validação de CPF, falarei hoje sobre a validação de CNPJ. Mas como o cálculo é bem parecido, vou destacar apenas as diferenças entre eles.

 

Para a validação do CPF, os pesos aplicados aos seus dígitos vão de 2 a 11. Para o CNPJ, os pesos vão de 2 a 9 e então reiniciamos os pesos (novamente em 2). E, assim como para o CPF, os pesos são aplicados da direita para a esquerda.


Vamos usar o CNPJ (gerado aleatoriamente) 90.306.453/0001-33 como exemplo.

Ao aplicarmos os pesos teremos as seguintes associações:

9
0
3
0
6
4
5
3
0
0
0
1

5

4

3

2

9

8

7

6

5

4

3

2

Sem contar o primeiro DV.

E

9
0
3
0
6
4
5
3
0
0
0
1
3
6
5
4
3
2
9
8
7
6
5
4
3
2

Contando o primeiro DV.


Como a partir da aplicação dos pesos o algoritmo é exatamente o mesmo ao do CPF, vamos direto para o código.

 

from itertools import cycle

LENGTH_CNPJ = 14


def is_cnpj_valido(cnpj: str) -> bool:
if len(cnpj) != LENGTH_CNPJ:
return False

if cnpj in (c * LENGTH_CNPJ for c in "1234567890"):
return False

cnpj_r = cnpj[::-1]
for i in range(2, 0, -1):
cnpj_enum = zip(cycle(range(2, 10)), cnpj_r[i:])
dv = sum(map(lambda x: int(x[1]) * x[0], cnpj_enum)) * 10 % 11
if cnpj_r[i - 1:i] != str(dv % 10):
return False

return True


if __name__ == "__main__":
print("CNPJs inválidos")
print(is_cnpj_valido("0"))
print(is_cnpj_valido("123456789012345"))
print(is_cnpj_valido("5" * LENGTH_CNPJ))
print(is_cnpj_valido("90306453000103"))
print(is_cnpj_valido("90306453000130"))
print("CNPJs válidos")
print(is_cnpj_valido("90306453000133"))
print(is_cnpj_valido("82671952000100"))
print(is_cnpj_valido("31049514000165"))
print(is_cnpj_valido("77437514000133"))
print(is_cnpj_valido("00059549000151"))


Temos apenas 3 diferenças entre os códigos de validação de CNPJ e CPF, que são:

1. A importação da função "cycle" do pacote "intertools"

2. O tamanho da constante que é 14 para CNPJ

3. O método da aplicação dos pesos.


Como são apenas estas as diferenças, e a importação e o tamanho da constante não precisam maiores explicações, vou explicar apenas a parte dos pesos. (Para a explicação do restante do algoritmo, acesse o post do CPF).


Para aplicar os pesos do CPF, nós fazemos uso da função "enumerate", porém não podemos fazer o uso da mesma função para o CNPJ, pois os pesos do CNPJ não são sequenciais, uma vez que a sequência é reiniciada ao atingir o valor 9.

Para atendermos esta particularidade, fazemos uso de 3 funções: "range", "cycle" e "zip". Como todas são funções que merecem posts específicos para explicá-las, vamos apenas resumir como elas agem no algoritmo.

A função range irá nos retornar um iterável que se inicia em 2 e termina em 9 (o 10 não é incluso).

Este iterável é recebido pela função cycle, que por sua vez devolve um objeto "itertools.cycle". Vamos dizer que esse objeto é tipo um "iterável infinito", pois se fizermos um "for" nele, o loop "nunca" será finalizado.

Por fim pegamos este "iterável infinito" e o iterável com os dígitos invertidos do CNPJ e passamos para a função zip. A função irá unir estes 2 iteráveis, limitando o resultado pelo tamanho do menor iterável (neste caso o CNPJ). Com isso teremos todos os dígitos do CNPJ com seus respectivos pesos aplicados, similar ao que a função enumerate faz com o CPF.

A partir daqui segue igual ao que é feito com o CPF.

Ler

13 de outubro de 2020

Python: Particularidades com números em Python


Como executar seu código python diretamente no Sublime-Text | by Willyan  Guimarães | experienceCode | Medium 

No post de hoje vou mostrar algumas particularidades quando estamos tratando números em Python.


Imagine que eu tenho um número 25555777, quando olhamos para ele fica um pouco complicado de rapidamente saber qual número é, mas em Python podemos utilizá-lo de maneira mais amigável ao ser humano como 25_555_777 pronto fica muito mais fácil de saber que o número é 25 milhões, 555 mil e 777, o compilador entende isso normalmente.

Outro exemplo é quando eu quero utilizar apenas a parte inteira de um número decimal, por exemplo 7 / 3 é 2,33333, caso queira saber apenas qual o número inteiro ignorando a parte decimal eu poderia converter com um cast int (7 / 3) que ele me retornaria 2, mas um forma mais fácil e rápida seria 7 // 3 com duas barras, também me retornará 2. Inclusive pode ser utilizado em cálculos mais extensos.

Mais uma seria particularidade é que os números não tem o mesmo limite que outras linguagens, um inteiro pode ter o tamanho até que a memória da máquina suporte e não o tamanho do tipo inteiro.

Ler

6 de outubro de 2020

SQL: Selecionar apenas os decimais dos números


SQL Server Express - Backup, Recursos, Comparando edições
No post de hoje vamos ver como selecionar apenas os decimais de um número no SQL Server.

É bem simples, para demonstrar isso vou declarar uma variável decimal.
declare @teste decimal(4,3)

Setar um valor com casas decimais.
select @teste = 2.938

E executar o comando:
select PARSENAME(@teste, 1)

Na verdade essa é uma função mais utilizada para tratamento de texto, mas para esse caso funciona, o que o parsename faz é separar o texto pelo "." no caso separando o "2" do "938".

Confira também a documentação oficial.
Ler

1 de outubro de 2020

Python: Uma função Pythônica para validar CPF


 


Algoritmos para validação de CPF são alguns dos primeiros algoritmos que aprendemos em cursos de programação (pelo menos foi assim comigo).

CPFs são compostos por 11 dígitos, sendo que os 2 últimos são dígitos verificadores. Portanto, para sabermos se um CPF é ou não válido, precisamos realizar o cálculo (que foi definido pela Receita Federal) e comparar o resultado obtido com os valores do dígito verificador.
 
O cálculo é bem simples! Vamos imaginar o seguinte CPF:
504.065.090-69 (CPF gerado aleatoriamente)
Primeiro pegamos os 9 primeiros dígitos e aplicamos a cada um deles um peso que se inicia em 2, da direita para a esquerda.

5

0

4

0

6

5

0

9

0

10

9

8

7

6

5

4

3

2

 
Após isso, basta somarmos cada dígito multiplicado por seu peso:
5 * 10 + 0 * 9 + 4 * 8 + ... + 0 * 2 = 170
 
Com este resultado, podemos optar entre 2 cálculos:
 
11 - 170 % 11

ou
 
170 * 10 % 11
 
Obs.: Lembrando que "%" é usado para calcular o resto (módulo) da divisão na maioria das linguagens de programação.
Ambos os cálculos nos levará ao valor do primeiro dígito verificador, que para este exemplo é 6.

Agora basta fazermos o mesmo calculo anterior, mas considerando também o primeiro dígito.
Os pesos ficarão conforme abaixo:
 

 5

0

4

0

6

5

0

9

0

6

11

10

9

8

7

6

5

4

3

2

 

Como a partir daqui o cálculo é exatamente o mesmo, vamos então para o algoritmo em Python!

TAMANHO_CPF = 11


def is_cpf_valido(cpf: str) -> bool:
if len(cpf) != TAMANHO_CPF:
return False

if cpf in (c * TAMANHO_CPF for c in "1234567890"):
return False

cpf_reverso = cpf[::-1]
for i in range(2, 0, -1):
cpf_enumerado = enumerate(cpf_reverso[i:], start=2)
dv_calculado = sum(map(lambda x: int(x[1]) * x[0], cpf_enumerado)) * 10 % 11
if cpf_reverso[i - 1:i] != str(dv_calculado % 10):
return False

return True


if __name__ == "__main__":
print(is_cpf_valido("0"))
print(is_cpf_valido("123456789012345"))
print(is_cpf_valido("55555555555"))
print(is_cpf_valido("19627722000"))
print(is_cpf_valido("19627722091"))
print(is_cpf_valido("19627722090"))
print(is_cpf_valido("02927367035"))
print(is_cpf_valido("64935775009"))
print(is_cpf_valido("45508834052"))
print(is_cpf_valido("50406509069"))

Na linha 1 apenas definimos uma constante com o tamanho do CPF.
 
Na linha 4 temos a declaração da nossa função.
 
Na linha 5 realizamos nossa primeira validação. Se o CPF não tiver exatamente 11 caracteres retornamos que o CPF informado é inválido. (lembre-se de limpar a mascara do CPF antes de chamar esta função).
 
Na linha 8 validamos se não é um CPF inválido conhecido (111.111.111-11, 222.222.222-22, ..., 000.000.000-00). Esta validação é feita a partir de um iterável gerado com uma comprehension. A comprehension irá iterar sobre cada valor da string "1234567890" e irá multiplicar cada caractere pelo tamanho do CPF. Aqui temos 2 particularidades sobre strings no Python:
1. Strings são iteráveis
2. Quando multiplicamos uma string por um valor inteiro, o resultado obtido será aquela string repetida x vezes.
 
Exemplo:
"a" * 10 = 'aaaaaaaaaa'
 
Na linha 11 o CPF informado é invertido. Exemplo:
De 12345678910 para 01987654321
A inversão é feita para facilitar a aplicação dos pesos.
 
Na linha 12 nós declaramos um for que irá iterar 2x, iniciando em 2 e finalizando em 1.

Na linha 13 é onde aplicamos os pesos de cada digito do CPF.
Primeiro nós pegamos o CPF invertido e fazemos uma substring delete que vai de "i" até o final.
Então pegamos esta substring e aplicamos os pesos nela, através da função "enumerate".
A função enumerate merece um post só para ela. Mas, de maneira resumida, ela recebe um iterável e enumera cada posição deste iterável. Ela retorna um "enumerate object" (que é também um iterável) de tuplas. Podemos converter este "enumarete object" em uma lista, por exemplo.
 
Exemplo:
list(enumerate([1, "b", 3])) = [(0, 1), (1, 'b'), (2, 3)]

Obs.: Vale atentar que no nosso caso nós iniciamos a função enumerate em 2 e não em 0.
 
A linha 14 é onde aplicamos o cálculo explicado no começo do post.
Primeiro multiplicamos os dígitos por seus respectivos pesos através da função "map". Assim como a função enumerate, a função map merece um post só para falar dela, mas vamos para um resumo. Ela recebe uma função e um iterável, e a partir disso gera um novo iterável.
No nosso exemplo, a função informada é uma expressão lambda (que resumidamente é uma função anônima) e o enumerate object criado na linha anterior. É na expressão lambda que ocorre a multiplicação dos digitos pelos seus pesos.
Usamos então função sum para somar o iterável retornado pela função map e aplicamos o resto da fórmula.

Na linha 15 nós comparamos o dígito do CPF informado com o dígito calculado. Caso os valores sejam diferentes, retornamos que o CPF é inválido.
A única observação que cabe aqui (além da conversão do dígito calculado para string) é que nós comparamos o módulo do dígito calculado por 10. Fazemos isso, pois quando o módulo da divisão por 11 resulta em 10, o valor que deve ser considerado é 0.

Como dito anteriormente, o loop será executado 2x. E caso não haja nenhuma inconsistência, a função irá retornar que o CPF é válido (linha 18).

Ler

29 de setembro de 2020

Gestão de projetos: Gráfico de Gantt o que é e como funciona


 


Gráfico de Gantt ou Diagrama de Gantt é usado para controlar visualmente um cronograma, muito conhecido e utilizado na gestão de projetos, pois ele auxilia a se ter uma avaliação rápida do status do projeto, quais tarefas foram executadas, prazos de entrega, dependências, tudo com intervalo de tempo.

O gráfico foi criado pelo norte americano Henry Gantt na década de 20 que se inspirou em Harmonogram criado pelo engenheiro polonês Karol Adamiecki. A ideia de Henry era evitar atrasos na produção de fábricas.
Ele trás vários benefícios como por exemplo:
  • Mostrar de maneira clara e visual o andamento do projeto
  • Segmenta tarefas, definindo a ordem e interdependência que elas devem ser executadas
  • Distribui responsabilidades (caso deseje adicionar isso ao gráfico)
  • Fácil visualização dos prazos das tarefas
Resumindo seu funcionamento:
Para criar seu gráfico de Gantt você precisará enumerar as tarefas que serão realizadas, colocá-las em sequência de cima para baixo (eixo Y) e na horizontal (eixo X) o tempo (pode ser definido em horas, período de trabalho, dias, etc) e conforme as tarefas vão sendo concluídas você vai preenchendo com retângulos esse espaço de tempo que a tarefa demorou a ser executada. Vejamos no exemplo abaixo um gráfico um pouco mais detalhado e extenso.
Existem várias ferramentas online para criação desses gráficos e gestão de projetos, inclusive o Excel também tem como criar gráficos de Gantt.
Ler

22 de setembro de 2020

CSS: Filtros (drop-shadow, grayscale, saturate, sepia e invert)


 


No post de hoje continuaremos falando de mais alguns filtros do CSS, caso não tenha visto o post anterior CSS: Filtros (opacity, brightness, contrast e blur)


Começando com o sepia, como o nome já diz ele vai converter a imagem em sépia, onde 0% significa a imagem original e 100% é sépia por completo, qualquer valor entre isso é uma mistura da original com o tom de sépia.

.filtered {

  filter:sepia(100%);

}


O filtro saturate vai mexer com a saturação da imagem onde eu posso adicionar ou remover a saturação onde 100% é a imagem original, então caso queira aumentar deve ser valores maiores que isso (200% por exemplo) e para diminuir pode colocar entre 0 e 99%.

.filtered {

  filter:saturate(80%);

}


Converte a imagem em escala de cinza quanto maior a porcentagem mais evidente fica a escala de cinza.

.filtered {

  filter:grayscale(100%);

}


Esse filtro cria uma sombra no objeto, nesse exemplo vou colocar uma sombra um pouco abaixo, para a direita com um leve desfoque e na cor cinza. A ordem dos parâmetros é a seguinte, sombra horizontal, sombra vertical, desfoque e cor.

.filtered {

  filter:drop-shadow(8px 8px 10px gray);

}


Esse filtro inverte as cores da imagem, semelhante ao que tínhamos nos negativos de fotos. O valor de 0% é da imagem original e 100% é a imagem totalmente invertida.

.filtered {

  filter:invert(100%);

}

Ler

15 de setembro de 2020

CSS: Filtros (opacity, brightness, contrast e blur)


No post de hoje irei mostrar alguns filtros bem interessantes do CSS. Principalmente utilizados em imagens.

Primeiro um dos filtros mais usados é o opecity, ele controla a opacidade do objeto, ele é muito utilizado para fotos, principalmente para fotos de fundo onde um texto ficará na sua frente dando assim uma melhor leitura. Para utilizá-lo é bem simples, apenas coloque a porcentagem de opacidade que deseja que o objeto fique.

.filtered {

  filter: opacity(70%);

}


Outro filtro seria o de brilho, bastante utilizado para dar um retoque de claridade a imagem ou para clarear a cor de um objeto de uma forma um pouco diferente do que apenas trocar a cor. No exemplo abaixo irei remover um pouco do brilho, por isso utilizo valores abaixo de 100%

.filtered {

  filter: brightness(50%);

}


Agora se não for o brilho que esteja faltando na imagem, mas sim o contraste o filtro a ser usado é o contrast, também definindo em porcentagem, no caso vou adicionar 40% ao contraste original da foto.

.filtered {

  filter: contrast(140%);

}


Este filtro causa um desfoque na foto, também muito interessante para usar em imagens de fundo com algum texto na frente. Segue um exemplo:

.blured {

  filter: blur(5px);

}

Ler

8 de setembro de 2020

Certificados digitais ganham cada vez mais importância





Os Certificados Digitais são como chaves eletrônicas que abrem também "abrem portas" garantindo a autenticidade e a segurança no mundo online. Ele está sendo cada vez mais usado por empresas de todos os tipos pois é muito vantajoso seu uso e de certa forma com um custo baixo fazendo com que o mercado cresça bastante.

Existem vários tipos de certificados, vamos falar sobre os principais:

Certificado A
Esse certificado vem na forma de assitura digital, como se fosse quando você assina um documento com caneta, ele é utilizado para "assinar" um documento ou transação, mostrando que é autentica com seu titular possuindo inclusive validade jurídica. É muito conhecido por ser usado em Notas fiscais, prescrições médicas digitais, leilões online, enfim uma infinidade de documentos digitais que se comparados com os físicos requiririam assinatura.

Ele existe em vários formatos onde cada um pode variar o tempo de validade ou a forma de se instalar no computador, sendo os mais conhecidos os A1 e A3.


Certificado S
Esse certificado é de sigilo, ou seja, ele criptografa os dados enviados na transação ou que serão armazenados com uma dupla de chaves onde apenas quem tem a chave pode decriptar. Ele também tem alguns subtipos S1, S2, S3 e S4, e suas diferenças estão ligadas ao armazenamento.


Certificado T
O certificado tipo T são de certa forma parecidos com o certificado do tipo A, mas com um adicional de time-stamping que significa “marca de tempo”. Então além de assinar um documento ou transação ele marca quando isso ocorreu com data e hora. Ele tem duas opções T3 e T4.
Ler

3 de setembro de 2020

Python: List Comprehension


 

 Recentemente comecei a estudar Python, e um dos recursos que mais achei interessantes foram as Comprehensions.

As comprehensions nada mais são que uma maneira sucinta de gerar novos objetos a partir de outros objetos iteráveis (listas, sets, dicts, etc). São muito utilizadas para substituir instruções for mais simples, ou funções como map e filter.

Neste artigo vou exemplificar apenas as List Comprehension, pois, além de serem as mais simples, a lógica para as demais (set, dict, etc) é a mesma, mudando apenas o tipo de dado a ser tratado.

A sintaxe mais básica de uma list comprehension é:

[expressão for item in iterável]

Exemplo:

 

Podemos condicionar os dados que queremos retornar com if.

[expressão for item in iterável if condição]

Exemplo:

 

Também podemos utilizar o else quando queremos condicionar nossos dados

[expressão se verdadeiro if condição else expressão se falso for item in iterável]

 

Para finalizarmos nosso post, vale ressaltar que onde temos a "expressão", podemos fazer uso de funções, mudar o tipo de dado a ser retornado, utilizar outra comprehension, enfim, as possibilidades são muitas. Mas é muito importante ter em mente que devemos sempre seguir os princípios descritos no "The Zen Of Python". Então se sua comprehension está ficando muito complicada e/ou complexa, talvez seja melhor fazer uso da boa e velha instrução for.


Até a próxima!

Ler

1 de setembro de 2020

SQL: DateDiff calculando datas


No post de hoje irei mostrar uma forma de se calcular datas no SQL, esse calcular seria realmente fazer a diferença de uma data para outra.

Para isso iremos usar a função DATEDIFF que como o nome bem intuitivo diz, nos retorn a diferença entre uma data inicial para uma data final e ainda permite que eu escolha entre vários tipos de retorno qual desejo (segundos, horas, meses etc.).

A sintaxe é DATEDIFF (TipoDeDado, DataInicial, DataFinal)

No tipo de dado os mais comuns são:
  1. year
  2. month
  3. day
  4. hour
  5. minute
  6. second
  7. millisecond

Um exemplo para ilustrar seria SELECT DATEDIFF(day, '2020-09-01', '2020-09-03')

A lista completa pode ser vista na documentação oficial: Microsoft
Ler

18 de agosto de 2020

C#: Limitando retorno de registros LINQ


 Seguindo com o LINQ vamos ver hoje como limitar o número de registros.

Caso não tenha visto os posts anteriores sugiro que dê uma conferida, neles falamos de Ordenação e Agregação.


Tendo como base a mesma classe e lista do exemplo anterior:

Aula
{
    Id int
    NomeAula string
    Curso int
    TempoDuracao datetime
}

List<Aula> aulas;

Imagine que quero saber quais são as 5 aulas com maior tempo de duração, primeiramente tenho que ordenar pelo tempo de duração, no caso como quero as de maior tempo a ordenação é descendente (do maior para o menor) e utilizo o método Take passando 5 como parâmetro.

var cursos = db.Cursos.OrderByDescending(c => c.TempoDuracao).Take(5);


Ou caso eu queira apenas a de maior tempo de duração, mas quero também me certificar de que caso eu não tenha nenhuma aula cadastrada no curso não me retorne um erro, uso o método FirstOrDefault. E indico sempre usá-lo ao invés do First como garantia, por mais que saiba que a lista tenha valores.

var curso = db.Cursos.OrderByDescending(c => c.TempoDuracao).FirstOrDefault();

Ler

13 de agosto de 2020

Instalando o Ubuntu Server 20.04 LTS no Oracle VM VirtualBox


 

 

No post de hoje mostraremos uma maneira bem básica de se criar um servidor Ubuntu no Oracle VM VirtualBox.

Apesar da popularização dos ambientes em nuvem, uma VM não deixa de ser uma opção bem interessante para ambientes de desenvolvimento e/ou aprendizagem. Eu mesmo gosto bastante de criar VMs quando quero testar algum OS diferente, ou realizar alguns testes que podem acabar "crashando" o OS, ou ainda quando estou desenvolvendo algum projeto. Neste último caso eu geralmente configuro uma VM como um espelho do ambiente que terei em produção. Com isso posso realizar vários testes a vontade, sem me preocupar se vou ou não fazer alguma besteira, uma vez que basta voltar para o último snapshot válido, ou, no pior dos casos, reinstalar a VM.

Bom, mas chega de falação e vamos ao que interessa!

Antes de mais nada você precisará baixar e instalar o Oracle VM VirtualBox. Você pode baixar clicando aqui, ou pela loja de apps do seu OS.

Neste post não iremos mostrar como instalar o VirtualBox, mas é basicamente o padrão Next, Next, Next...

Uma observação importante! Talvez seja necessário que você habilite a configuração de virtualização na BIOS do seu computador.

 

O Ubuntu Server pode ser baixado clicando aqui, ou, se preferir, pelo site oficial https://ubuntu.com/.

 

Ao abrir o Oracle VM VirtualBox, você verá uma tela similar a esta:

 

Vamos agora criar a nossa VM clicando em Novo

Aqui iremos fazer a configuração básica da nossa VM, dar um nome, dizer o local onde os arquivos da VM ficarão salvos, o tipo do OS e a versão do OS (geralmente essas informações serão sugeridas de acordo com o nome que você der a sua VM). Também devemos informar a quantidade de memória RAM (neste caso vou usar 4GB) e se iremos criar um HD virtual ou utilizar um existente (ou não utilizar nenhum). Neste caso criaremos um novo.


Feito essas configurações, clicaremos em "Criar".

Agora a configuração é relacionada ao HD. Basicamente pede-se que informemos onde será salvo o HD virtual, o tamanho, o tipo e se será alocado dinamicamente ou não. Usaremos as configurações padrão, então basta clicar em "Criar".

 

Pronto! Com isso temos nossa configuração base. Agora vamos para a instalação do OS. Basta "Iniciar" a VM.


Ao iniciarmos, a primeira coisa que precisaremos fazer é informar o local da ISO que baixamos anteriormente. Após isso podemos então iniciar a instalação clicando em "Iniciar".


O processo será iniciado com o Ubuntu fazendo algumas checagens. E após isso, com tudo estando OK, ele pedirá para que selecionemos o idioma de instalação.

Obs: A partir daqui toda as configurações serão feitas pelo teclado.

Selecione o idioma desejado através das setas do teclado e pressione "Enter".


O próximo passo é selecionar o layout do teclado. Provavelmente o Ubuntu já conseguiu identificar sozinho, mas caso não basta alterar a configuração para a do seu teclado.


A próxima configuração é a de rede. Manteremos a configuração padrão.


Agora nos é pedido uma configuração de proxy. Caso você utilize algum proxy, basta informá-lo no respectivo campo. Senão, basta seguir com a instalação.


A próxima configuração é a do mirror do Ubuntu. De maneira simples, este mirror é onde está localizado o repositório do Ubuntu. Aqui temos uma lista dos principais mirrors disponíveis por país. Mas não é necessário alterar esta configuração, portanto apenas continuaremos com a instalação.


Chegamos agora na configuração do storage do sistema. Aqui podemos particionar o disco que criamos anteriormente como bem entendermos. Porém, como não é a intenção deste post falar sobre sistemas de arquivos e partições, iremos adotar a configuração sugerida na instalação.


Temos agora o resumo das configurações do storage.


Ao seguir com a instalação será exibida uma mensagem de confirmação com alguns alertas sobre a instalação.


O próximo passo é informar os nossos dados de usuário e o nome do nosso computador.


Temos agora a opção de instalar um servidor OpenSSH. Como também não é intenção deste post falar sobre SSH, continuaremos o processo sem instalar o OpenSSH


Por fim, temos a possibilidade de instalar vários outros recursos, como por exemplo o aws-cli, que realiza integração com o Amazon AWS, ou o cliente para ingreção com o Heroku, entre outros. Caso você utilize algum dos serviços listados, você pode selecioná-los neste momento. Ou também pode instalá-los posteriormente.


A partir deste momento a instalação será iniciada, e, quando for finalizada, será solicitado que reiniciemos a máquina.

Obs: É comum acontecer um erro na hora de reiniciar, geralmente quando o sistema tenta "desmontar" a ISO. Caso isso ocorra com você, basta pressionar "Enter" que o sistema irá reiniciar normalmanete. Mas se mesmo assim o sistema não reiniciar, basta fechar a janela pedindo para desligar a máquina, e então iniciar novamente o servidor.


Pronto! Após a reinicialização poderemos logar no sistema utilizando o usuário que criamos durante a instalação.


Mas antes de finalizarmos o post aqui, vamos criar um snapshot do nosso servidor. Então vamos começar desligar nosso servidor digitando o comando "shutdown now".

Quando o servidor for desligado, sua janela será fechada automaticamente.

Voltamos agora para o VirtualBox e vamos clicar nas opções do nosso servidor e selecionar a opção "Snapshots".


Basta então clicar "Criar". Será pedido para darmos um nome para nosso snapshot, assim como uma descrição.


Feito! A partir daqui podemos utilizar nosso servidor recém criado, e caso haja algum problema, basta restaurar este snapshot.

 

É interessante sempre criar snapshots antes e após alterações relevantes do sistema, como uma atualização, por exemplo. Isso fará com que não tenhamos muitos "prejuízos" se precisarmos restaurar o sistema.


E com isso finalizamos nosso post! Até a próxima!

Ler

11 de agosto de 2020

C#: Funções de agregação LINQ


Seguindo o post anterior de LINQ sobre ordenações  vamos ver algumas funções de agregação.

Tendo como base a mesma classe e lista do exemplo anterior:

Aula
{
    Id int
    NomeAula string
    Curso int
    TempoDuracao datetime
}

List<Aula> aulas;

Primeiramente quero saber quais aulas tem o maior tempo, a que tem o menor tempo e a média de tempo de todas elas.

Para saber a de maior usarei o Max:
var max = aulas.Max(c => c.TempoDuracao);

Para saber a de menor o Min
var min = aulas.Min(c => c.TempoDuracao);

E para a média o Average
var media= aulas.Average(c => c.TempoDuracao);

Uma outra opção bem interessante é contar quantos registros existem seguinte uma regra que eu definir, por exemplo, quero saber quantas aulas tem Engenharia no nome, para isso utilizo o Count para contar e dentro dele utilizo o Contains para comparar as strings.
int total = aulas.Count(c => c.NomeAula.Contains("Engenharia"));
Ler

6 de agosto de 2020

Transferência de dados CLOB entre bancos Oracle, via DB Link




Uma vez, ao implementar um programa que precisava comunicar dois bancos de dados Oracle 11g diferentes, e em tempo real, uma limitação do próprio banco de dados em enviar de dados CLOB de um banco para o outro via DB link tornou-se um grande problema. Caso este problema não fosse contornado de alguma maneira, não seria possível fazer a integração entre os bancos em tempo real. Como esta limitação está relacionada ao tamanho que os dados CLOB comportam, a solução foi dividir as informações a serem transferidas em blocos informações menores e em um tipo de dado que permitisse a transferência das informações entre os bancos de dados, neste caso, o VARCHAR2.

Mas o que é um DB Link?
Conforme a documentação fornecida pela Oracle, um DB Link é um objeto de esquema que permite o acesso aos objetos à partir de outro banco de dados.
Após a criação do link, é possível acessar os objetos do outro banco através de instruções SQL, adicionando "@nomedblink" logo após o nome do objeto. Também é possível executar outras instruções SQL, como por exemplo INSERT, UPDATE, DELETE, LOCK TABLE.

Por sorte, a própria Oracle já fornece algumas funções para a manipulação de dados de tipo "LOB" (Large Objects). Estas funções se encontram dentro do pacote "dbms_lob".

Para a solução deste problema foram usadas apenas 4 funções, que são:

Função "dbms_lob.substr"
Utilizada para ler um tipo de dado CLOB, NCLOB ou BLOB à partir de um offset ("deslocamento").
"[…] É uma função passada-por-valor que retorna um tipo de dados RAW para tipos BFILE e BLOB e VARCHAR2 para CLOB ou NCLOB. [...]" (MCLAUGHLIN, 2009, p.311).
Em outras palavras, com esta função é possível retornar um pedaço de um texto armazenado dentro de um campo CLOB, por exemplo.

Função "dbms_lob.createtemporary"
Cria um BLOB, CLOB ou NCLOB temporário na memória. "[…] Os LOBs temporários são entidades de limite de tempo[...]" (MCLAUGHLIN, 2009, p.313), ou seja, somem da memória assim que o processo é finalizado (ou assim que são explicitamente "destruídos").

Função "dbms_lob.append"
É utilizado para adicionar conteúdos ao final de um LOB. (MCLAUGHLIN, 2009, p.304).

Função "dbms_lob.freetemporary"
É utilizado para liberar a memória consumida por um BLOB, CLOB ou NCLOB criado através da função "dbms_lob.createtemporary". Recomenda-se que esta função sempre deva ser utilizada ao trabalhar com LOBs temporários. (MCLAUGHLIN, 2009, p.313).

Implementação

Para o desenvolvimento deste exemplo fez-se uso do banco Oracle 11g Express Edition, por ser uma versão gratuita.
A título de exemplificação, foram criados 2 usuários. "user_emissor" e "user_externo". O usuário "user_emissor" representará o banco de dados que contém a origem das informações, ou seja, que contém a tabela com uma coluna do tipo de dado CLOB. Já o usuário "user_externo" representará um banco de dados externo que precisa fazer o acesso ao banco proprietário das informações ("user_emissor").
Para que a comunicação entre os usuário seja possível, é necessária a criação de pelo menos 2 objetos. Sendo um pacote que fará a serialização do CLOB num vetor de VARCHAR2 no usuário "user_emissor", e uma função que concatenará o vetor novamente em CLOB no usuário "user_externo". No exemplo também será criada uma view no usuário "user_externo". A implementação desta view não é obrigatória, mas facilitará a exibição dos dados.

Estrutura da tabela "exemplo_clob":
Dentro do esquema do usuário "user_emissor" existe a tabela "exemplo_clob".

Diagrama Tabela "exemplo_clob".

Esta é a tabela que precisa ser acessada pelo usuário "user_externo".
Ela possui apenas duas colunas, sendo uma para a identificação de seus registros ("id_exemplo_clob"), e outra coluna ("texto") que armazena as informações que precisam ser lidas pelo usuário "usuario_externo".


Pacote "PKG_LOB"

Para que a integração entre os bancos de dados seja possível, é necessária a implementação de um pacote que contenha a definição de um objeto do tipo TABLE. É através deste pacote que o usuário "user_externo" irá ter acesso à estrutura de dados em que o CLOB foi serializado.

Estrutura do pacote "pkg_lob". É através dela que o usuário "user_externo" terá acesso às informações do CLOB serializado.


A figura acima tem um exemplo da definição do pacote, e abaixo o detalhamento desta estrutura:
A linha 1 corresponde à instrução de criação do pacote
A linha 2 marca o início das definições do pacote. É a partir dela que todos os objetos e procedimento são definidos. Todos os objetos e procedimento públicos, ou seja, que podem ser acessados por outros objetos/usuário, devem estar descritos neste bloco.
Na linha 4 está a declaração de uma estrutura de dados do tipo TABLE OF VARCHAR2(4000). É a partir desta estrutura que os objetos de manipulação do CLOB serão montados. O tamanho do VARCHAR2 é de 4000, pois é o limite que uma instrução SELECT pode manipular.
Nas linhas 8 à 10 tem-se a definição da função que irá fazer a serialização do CLOB num vetor de VARCHAR2. Entre elas, na linha 9, está a declaração de um parâmetro de entrada que será utilizado para filtrar a informação desejada. Deve-se atentar à linha 10, pois ela define o retorno da função como sendo a estrutura de dados criada anteriomente.
Por fim, a linha 12 marca o final da declaração do pacote.


Corpo do pacote

Estrutura do corpo do pacote "pkg_lob". Contém o algoritmo que faz a serialização do CLOB num vetor VARHCAR2.

O corpo do pacote é onde está contida toda a lógica (figura acima). Abaixo segue o detalhamento de sua estrutura:

A linha 1 corresponde à instrução de criação do corpo do pacote.
A linha 2 marca o início das declarações de todos os objetos e procedimentos acessíveis dentro do pacote. Nenhum objeto e/ou procedimento que esteja dentro desta declaração será público, exceto para os casos dos procedimentos estejam declarados na estrutura do pacote que permite o acesso externo.
Entre as linhas 6 e 38 está a função responsável por fazer a serialização do CLOB no array de VARCHAR2.
As linhas 6 a 8 criam a definição da função. Esta deve estar exatamente igual ao que foi definido na estrutura principal do pacote.
Entre as linhas 9 e 11 está a declaração da variável "v_array" do tipo TabArray, onde TabArray é o objeto TYPE criado na definição do pacote, e a declaração de uma constante ("c_max_length"), que armazena o valor máximo de cada bloco VARCHAR2 do vetor.
A linha 14 faz a inicialização do objeto vetor.
Na linha 17 está a declaração do loop que fará a serialização do CLOB em VARCHAR2.
Entre as linhas 18 e 24 estão as instruções SELECT que fazem a serialização do CLOB em VARCHAR2. Para que seja possível o entendimento desta instrução, precisa-se olhar do SELECT interno para o SELECT externo. O SELECT interno faz uso da função CEIL com a função LENGTH (linha 20). A função LENGTH faz a contagem da quantidade de caracteres contidos no CLOB. Este resultado é divido pela constante "c_max_length", que é o limite de caracteres definido para este exemplo. Ao resultado desta divisão é aplicada a função CEIL. Esta função faz com que um valor que contenha casas decimais seja arredondado para o próximo valor inteiro. Exemplo: CEIL(4,01) = 5. A este resultado da-se o alias (apelido) de "qtd_linhas"
Logo abaixo, na linha 21, o SELECT retorna a coluna "texto", que é a coluna que contém o(s) valor(es) CLOB(s) a ser(em) serializado(s).
Na linha 23 o parâmetro "pi_id_exemplo_clob" é utilizado para filtrar apenas um registro da tabela e fazer a serialização das informações deste registro.
Com base nas informações retornada pelo SELECT interno, o SELECT externo faz a serialização dos dados CLOB através da combinação da clausula CONNECT BY com a função "dbms_lob.substr". Ao utilizar a cláusula CONNECT BY com o resultado de "qtd_linhas" faz-se com que o SELECT retorne uma quantidade de linhas igual ao valor de "qtd_linhas", ou seja, se "qtd_linhas" for igual a 7, o SELECT retornará 7 linhas, por exemplo. O identificador de cada linha fica por conta da função "LEVEL", que retorna qual é a posição de cada linha na hierarquia.
O resultado de "LEVEL" possui 2 utilidades, definir o índice das posições do vetor (linha 19), e, junto da função "dbms_lob.subtr", realizar a divisão do CLOB em blocos de VARCHAR2 (linha 21).
As linhas 25 e 33 marcam, respectivamente, o início e o fim do bloco que carrega o vetor.
A linha 28 cria, através da função "EXTEND", uma nova posição para o vetor "v_array".
A linha 31 define o índice de "v_array" com o valor de "LEVEL" (ao qual foi dado alias de "i") e atribui na posição deste índice o bloco de VARCHAR2 gerado pelo SELECT.
Ao finalizar todas as iterações do loop, o vetor "v_array" é retornado através da instrução "RETURN" (linha 37).
A linha 38 marca o final da função, e a linha 44 marca o final da declaração do corpo do pacote.

Partimos agora para a função "get_exemplo_clob_texto". É através dela que a desserialização do CLOB é feita. Ela também é responsável por criar o vínculo entre os usuários "user_externo" e "user_emissor".

Estrutura da função "get_exemplo_clob_texto". É responsável por fazer a desserialização do vetor e retornar um CLOB.


As linhas 1 e 3 marcam definição da função, que é igual à função que está dentro do pacote "pkg_lob" no usuário "user_emissor", exceto pelo tipo de dado a ser retornado, que, neste caso, é um CLOB.
Entre as linhas 5 e 7 estão declaradas 3 variáveis. Uma do tipo TabArray ("v_array") e duas do tipo CLOB ("v_temp" e "v_texto"). É importante perceber que a declaração da variável "v_array" é feita com o uso do DB link, fazendo referência ao objeto TabArray do pacote "pkg_lob", que pertence ao usuário "user_emissor". É aqui onde encontra-se todo o segredo por trás do algoritmo, pois a estrutura que é utilizada para criar o vetor passa a ser compartilhado por ambos os usuários.
Entre as linhas 12 e 14 está a chamada para a função "pkg_lob.get_exemplo_clob_texto" e armazena o valor que ela retorna dentro da variável "v_array".
Após isso, na linha 17, um objeto temporário do tipo CLOB é criado através da variável "v_temp" e a função "dbms_lob.createtemporary".
O bloco entre as linhas 20 e 22 é responsável por varrer todo o vetor, e concatenar os dados contidos dentro de cada um dos blocos deste vetor na variável "v_temp", através da função "dbms_lob.append".
Após este processamento, o resultado obtido em "v_temp" é atribuído à variável "v_texto" (linha 25), e, logo em seguida, a variável temporária "v_temp" é eliminada da memória com o uso da função "dbms_lob.freetemporary" (linha 28).
Por fim, na linha 31, a função devolve os dados que foram inicialmente recebidos de maneira serializada, como se fosse originalmente um dado do tipo CLOB.
A linha 33 marca o final de todo o bloco correspondente à função.


Visualização dos dados através da view "VIEW_EXEMPLO_CLOB"

A estrutura da view é feita de maneira que de a impressão ao usuário que ela nada mais é que um "espelho" da tabela "exemplo_clob". Assim como a função "get_exemplo_clob_texto", ela também é implementada no lado do usuário "user_externo".

Estrutura da view "view_exemplo_clob". Criada para facilitar o acesso às informações da tabela "exemplo_clob" do usuário "user_emissor".

Abaixo segue o detalhamento de sua estrutura:
A primeira linha é onde defíne-se o nome da view.
A linha 2 marca o ponto à partir de onde será criado a instrução da consulta.
Entre as linhas 3 e 5 está a instrução da consulta utilizada para retornar os dados. Na linha 3 para o ínico da consulta através da cláusula "SELECT". Junto da instrução "SELECT" está a coluna "id_exemplo_clob" da tabela "exemplo_clob". A linha 4 faz uso da função "get_exemplo_clob_texto" e informa o "id_exemplo_clob" como parâmetro da função. Isso significa que será buscado o texto correspondente à identificação da linha que está sendo processada. Por fim, na linha 5 está identificada a fonte dos dados, ou seja, a tabela "exemplo_clob". Como esta tabela não pertence ao usuário "user_externo", faz-se necessário o uso do DB link para que as informações sejam acessdas.
A linha 6 marca o final do script de criação da view.

Comparando os resultados

A fim de mostrar a eficácia deste método, duas consultas exatamente iguais são executadas, uma para cada um dos usuários. Exceto que para o usuário "user_emissor" a consulta será em cima da tabela "exemplo_clob", enquanto no usuário "user_externo" a consulta é em cima da view "view_exemplo_clob". Porém isto não afeta o resultado, uma vez que a fonte de dados da view é a tabela "exempl_clob", ou seja, extamente a mesma fonte de dados utilizada para o usuário "user_emissor".

Execução da consulta no usuário "user_emissor":

Consulta no usuário "user_emissor"

Execução da consulta no usuário "user_externo":

Consulta no usuário "user_externo".


Como uma coluna CLOB pode armazenar um valor muito grande (e que talvez não seja possível visualizar por completo, como é o caso deste exemplo), a função "LENGHT" foi utilizada para realizar a comparação do tamanho do texto retornado em cada usuário. Como podemos observar, o resultado para ambos os usuários foi exetamente igual, "18346" caracteres. Isso mostra que toda a serialização e desserialização destes dados ocorreu como o esperado, uma vez que nenhuma informação foi perdida, ou acressida.

Referências

WATSON, John; RAMKLASS, Roopesh. OCA Oracle Database 11g: Fundamentos I SQL. Rio de Janeiro: Alta Books, 2008. 564 p.

MCLAUGHLIN, Michael. Oracle Database 11g: PL/SQL Programação. Rio de Janeiro: Alta Books, 2009. 830 p.

ORACLE. CREATE DATABASE LINK. 2005. Disponível em: <https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5005.htm>. Acesso em: 15 abr. 2017.

ORACLE. HIERARCHICAL QUERIES 2005. Disponível em: <https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm>. Acesso em: 18 mai. 2017.

ORACLE. HIERARCHICAL QUERIES PSEUDOCOLUMNS 2005. Disponível em: <https://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns001.htm#i1009261>. Acesso em: 18 mai. 2017.

ORACLE. DBMS_LOB 2005. Disponível em: <http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lob.htm>. Acesso em: 18 mai. 2017.
Ler