segunda-feira, 3 de outubro de 2022

ETL e análise de dados com Apache Spark (PySpark)

Já não se faz mais ETL como antigamente. O bom e velho Excel já não atende mais as necessidades das profissionais que trabalham com isso e deu lugar a ferramentas específicas para essa atividade (Talend, Apache Hop, SSIS). Até mesmo ferramentas de self service BI, possuem funcionalidades para realizar esse trabalho. Os Pythonistas de plantão já contavam com a Biblioteca Pandas para realizar esse trabalho, porém ao submeter um volume estrondoso de dados ao um script utilizando a dita cuja, percebe-se que ela não segura o rojão. Foi necessária a criação de uma ferramenta que possibilita-se o processamento distribuído dos dados. Surge então o ecossistema Hadoop, e mais a frente, o Apache Spark.

A ideia aqui é apresentar de forma prática a utilização do Spark, interagindo com ele através da SDK PySpark. O script lê 5 datasets, faz a conversão deste para dataframe e seguida, converte eles para views de modo a permitir a interação com os dados através de SQL.

import pyspark
from pyspark.sql import SparkSession

spark = SparkSession.builder.master('local[*]').getOrCreate()

clientes = spark.read.csv("C:\\Users\\gugum\\dados\\clientes.csv",
sep=';', inferSchema=True,header=True)
vendedores = spark.read.csv("C:\\Users\\gugum\\dados\\vendedores.csv",
sep=';', inferSchema=True,header=True)
produtos = spark.read.csv("C:\\Users\\gugum\\dados\\produtos.csv",
sep=';', inferSchema=True,header=True)
vendas = spark.read.csv("C:\\Users\\gugum\\dados\\vendas.csv",
sep=';', inferSchema=True,header=True)
itensvendas = spark.read.csv("C:\\Users\\gugum\\dados\\itensvenda.csv",
sep=';', inferSchema=True,header=True)

clientes.createOrReplaceTempView("clientesView")
produtos.createOrReplaceTempView("produtosView")
vendedores.createOrReplaceTempView("vendedoresView")
vendas.createOrReplaceTempView("vendasView")
itensvendas.createOrReplaceTempView("itensvendasView")

df_desnormalizado = spark.sql("""select
itensvendasView.IdProduto,
itensvendasView.Quantidade,
itensvendasView.ValorUnitario,
itensvendasView.ValorTotal,
itensvendasView.Desconto,
vendasView.IDVenda,
vendasView.Data,
vendasView.Total,
produtosView.IDProduto,
produtosView.Produto,
produtosView.Preco,
clientesView.Cliente,
clientesView.Estado,
clientesView.Sexo,
clientesView.Status,
vendedoresView.IDVendedor,
vendedoresView.Nome
from itensvendasView
inner join vendasView on vendasView.idvenda = itensvendasview.idvenda
inner join produtosView on produtosView.idproduto = itensvendasview.idproduto
inner join clientesView on clientesView.idcliente = vendasview.idcliente
inner join vendedoresView on vendedoresview.idvendedor  =  vendasview.idvendedor
""")

#vendas por cliente
teste2 = spark.sql("""select
distinct clientesView.cliente,
round(sum(itensvendasView.valorunitario)) as total_vendas
from itensvendasView
inner join vendasView on vendasView.idvenda = itensvendasview.idvenda
inner join produtosView on produtosView.idproduto = itensvendasview.idproduto
inner join clientesView on clientesView.idcliente = vendasview.idcliente
inner join vendedoresView on vendedoresview.idvendedor  =  vendasview.idvendedor
--where clientesView.cliente = 'Bernardete Águeda'
group by clientesview.cliente
order by total_vendas desc
""")
teste2.show(250)
df_desnormalizado.to_csv("vendas.csv")

Ao final é feita uma análise dos dados processados e em seguida, é gerado um arquivo CSV com dados desnormalizados.

Lembrando que esse código foi escrito para fins didáticos. Numa solução feita para ambiente produtivo, as tarefas seriam separadas, formando um Pipeline a ser orquestrado e startado por alguma ferramenta do tipo Job Scheduling.

Até a próxima pessoal!

sábado, 1 de outubro de 2022

Orquestrando scripts python utilizando o pacote/biblioteca LUIGI

Em um outro post, falei de uma biblioteca chamada Pandas que serve para fazer a transformação de dados em Python. Hoje, vamos falar de uma alternativa de orquestrar Pipelines. Vejamos a biblioteca Luigi.



Vamos imaginar que você tenha dividido o seu trabalho da seguinte maneira:

$ python extracao_dos_dados.py

$ python limpeza_dos_dados.py

$ python juncao_dos_dados.py

$ python fazer_coisas_com_os_dados.py

Estas atividades são muito comuns em projetos de dados. Cada script realiza uma atividade, tudo "organizadinho". Esse conjunto de atividades é conhecido, no jargão da engenharia de dados como Pipeline. Daí toda vez que você for executar a pipeline como um todo, terá que executar cada um dos scripts. Quando estamos falando de um ou dois conjuntos de dados beleza, mas sabemos que não é assim que funcionam as coisas. Para cada conjunto de dados teríamos 4 scripts para realizar o processo mencionado acima. A medida que as pipelines se multiplicam, a situação fica muito complicada.

Daí um colega sugere de botar todas essas atividades num script só e depois uma rápida refatoração, o script faz_tudo.py pode ficar assim:

if __name__ == '__main__':

extracao_dos_dados()

limpeza_dos_dados()

juncao_dos_dados()

fazer_coisas_com_os_dados()

   

Isso é bastante simples de executar: $ python faz_tudo.py

Poderíamos também colocar tudo em um script bash, que chamaria esses scripts todos, em sequência, mas as deficiências serão mais ou menos as mesmas.

Ao avançar para um pipeline pronto para produção, há mais alguns aspectos a serem considerados além do código de execução de tudo. Em particular, o tratamento de erros deve ser levado em consideração:

try:

    extracao_dos_dados()

except ExtracaoDeDadosError as e:

    # handle this

Mas se encadearmos todas as tarefas individuais, acabamos com uma árvore de Natal de try/except:

try:

    extracao_dos_dados()

    try:

        limpeza_dos_dados()

        try:

            # Rapaz, aonde isso vai parar!

        except EvenMoreErrors:

            # ...

    except limpeza_dos_dadosError as e:

        # tratando limpeza_dos_dadosError

except extracao_dos_dadosError as e:

    # tratando extracao_dos_dadosError

Outro aspecto importante a considerar é como retomar um pipeline. Por exemplo, se as primeiras tarefas forem concluídas, mas ocorrer um erro no meio do caminho, como executaremos novamente o pipeline sem executar novamente as etapas iniciais bem-sucedidas? Poderíamos tratar com if.

# testando se uma tarefa já foi executada com sucesso.

if not i_got_the_data_already():

    # if not, run it

    try:

       limpeza_dos_dados()

    except limpeza_dos_dadosError as e:...

Percebe o quanto pode ficar complicado esse controle das pipelines, caso a pipeline seja implementada desta forma?

Para resolver essa situação de uma maneira mais elegante, eis que surgem diversas ferramentas para tratar esse problema entre elas está o pacote Luigi.

Luigi é uma ferramenta Python para gerenciamento de fluxo de trabalho. Ele foi desenvolvido pela Spotify, para ajudar a construir pipelines de dados complexos de trabalhos em lote. 

Alguns dos recursos úteis do Luigi incluem:

  • Gerenciamento de dependência
  • Pontos de verificação/recuperação de falhas
  • Integração / parametrização CLI
  • Visualização do gráfico de dependência

Existem dois conceitos principais para entender como podemos aplicar o Luigi ao nosso próprio pipeline de dados: Tarefas e Destinos. Uma tarefa é uma unidade de trabalho, projetada estendendo a classe luigi.Task e substituindo alguns métodos básicos. A saída de uma tarefa é um destino, que pode ser um arquivo no sistema de arquivos local, um arquivo no S3 da Amazon, ou ainda, algum dado em um banco de dados..

As dependências são definidas em termos de entradas e saídas, ou seja, se tarefa2 depende da tarefa1, significa que a saída da tarefa1 será a entrada da tarefa2.

Então vamos deixar de bla bla bla, partindo para a parte prática.

Para instalar o Luigi: $ pip install luigi

""" Trata-se de scripts que contem classes que extendem a
a classe luigi task
"""

import luigi
 
 #métodos que precisam ser implmentados
class Tarefa1(luigi.Task):
 #o método requires recebe as tarefas das quais ela depende.
 # neste caso a tarefa 1 não depende de nenhuma outra tarefa
    def requires(self):
        return []
 #o método output é a saída da tarefa que pode ou não virar entrada de
 #outra tarefa.
    def output(self):
        return luigi.LocalTarget("numbers_up_to_10.txt")
 #o método run é a implementação da tarefa o que ela faz.
    def run(self):
        with self.output().open('w') as f:
            for i in range(1, 11):
                f.write("{}\n".format(i))
 
class Tarefa2(luigi.Task):
    #veja que a tarefa2 depende da tarefa 1, ou seja, a tarefa 1 tem
    #que rodar primeiro para depois a tarefa dois rodar.
    def requires(self):
        return [Tarefa1()]
 
    def output(self):
        return luigi.LocalTarget("squares.txt")
 
    def run(self):
        with self.input()[0].open() as fin, self.output().open('w') as fout:
            for line in fin:
                n = int(line.strip())
                out = n * n
                fout.write("{}:{}\n".format(n, out))
                 
if __name__ == '__main__':
    luigi.run()

# para executar $ luigi -m run_luigi.py SquaredNumbers --local-scheduler

Este código apresenta duas tarefas: tarefa1 , que grava o número de 1 a 10 em um arquivo chamado numbers_up_to_10.txt , um número por linha, e tarefa2 , que lê esse arquivo e gera uma lista de pares number-square em squares.txt , também um par por linha.

Salve esse código em um arquivo chamado dag_luigi e execute o mesmo através da linha de comando.

$ luigi -m dag_luigi.py tarefa2 --local-scheduler

O primeiro argumento que estamos passando para o arquivo é o nome da última tarefa no pipeline que queremos executar. O segundo argumento simplesmente diz ao Luigi para usar um agendador local .

O Luigi cuidará de verificar as dependências entre tarefas, se a entrada de tarefa2 não estiver lá, então ele executará a tarefa tarefa1 primeiro, depois continuará com a execução.

Para criar uma tarefa, simplesmente precisamos criar uma classe que estenderá a classe luigi.Task e sobrescrever alguns métodos. Em particular:

  • require() deve retornar a lista de dependências para uma determinada tarefa — em outras palavras, uma lista de tarefas
  • output() deve retornar o destino da tarefa (por exemplo, um arquivo local, ou um a inserção dos dados em um Banco).
  • run() deve conter a lógica para executar

Luigi verificará os valores de retorno de require() e output() e construirá o gráfico de dependência entre as tarefas.

Para ver o gráfico de dependências e acompanhar a execução das tarefas,  o Luigi disponibiliza uma interface web que pode ser acessada através do endereço localhost:8082. Para disponibilizar essa interface rode no pronpt de comando a seguinte instrução em foreground $luigid ou em background $luigid --background

Interface web do luigi

Nem tudo são as mil maravilhas, o agendamento da execução da DAG é feita através do velho e bom Cron.

Existem outras alternativas e o apache Airflow é uma delas.

Bom pessoal, era isso. Obviamente tem mais coisa para ser estudada sobre essa biblioteca veja a documentação dela em https://luigi.readthedocs.io/en/stable/index.html




domingo, 21 de agosto de 2022

Datalake (Uma versão BIG DATA do DW clássico)

Houve um tempo em que era possível gerar relatórios gerenciais com dados extraídos das bases transacionais que subsidiam os sistemas de informação. Com o aumento do volume de dados, constatou-se que as consultas envolvidas na produção desses relatórios estavam comprometendo o desempenho dos sistemas.

No sentindo de resolver essa questão eis que surgem as bases de dados analíticas com dados extraídos de bases transacionais, modelados de forma dimensional de modo a otimizar a performance das consultas efetuadas. Surge aí o conceito de Data Warehouse,

Agora vamos imaginar um cenário com uma grande VARIEDADE de dados (estruturados, semiestruturados e não estruturados).

Quando se fala em BIG DATA, verifica-se que o mercado e as ferramentas até então usadas para trabalhar com dados, precisaram ser adaptadas para processar um volume e uma variedade maior de dados. E o quesito análise de dados não poderia ser deixado de lado. 

Há quem diga que um DATALAKE é uma versão moderna do DW clássico surgido nos anos 90. Assim como o Data warehouse, um Datalake é um armazém de dados corporativo com a diferença de que neste último, os dados contidos podem ser estruturados, semiestruturados, e não estruturados. Além disso, esse armazém de dados é hospedado em um ambiente distribuído (dados hospedados em um sistema de arquivos distribuído), escalável e tolerante a falhas.

Outra diferença entre Data Warehouse  e Datalake é a ordem de como as coisas acontecem. No caso do DW, as atividades do processo de trabalho é a extração de dados de banco de dados transacionais, transformação desses dados para um formato dimensional e em seguida, a carga desses dados em tabelas fato e tabelas dimensão, presentes no DW. No caso do Datalake, primeira é feita a ingestão  dos dados(extração), em seguida ocorre a carga desses dados no lake para a partir daí se faça a transformação destes dados. Esse processo é conhecido como ELT.

A estruturas que recebem os dados varia de projeto, mas basicamente é previsto uma área para receber os dados brutos, outra área para realização de transformações sobre os dados e por fim, uma área para manter um histórico dos dados. 

A ingestão dos dados para essas estruturas pode ser feita em lote (batch), aonde acumula-se os dados por um tempo ou ainda a  medida que os dados são gerados, sendo capturados em tempo real(streaming).  O Spark Streaming ou ainda um serviço de mensageria (Kafka ou RabbitMQ) podem ser utilizadas como ferramenta para apoiar o trabalho.

A medida que esses dados são trabalhados vão sendo armazenados nas devidas camadas. utilizando formatos diversos de BIG DATA( Parquet, ORC, AVRO) visando economia de espaço em disco e velocidade de consulta. Para apoiar esse trabalho, geralmente utiliza-se uma engine de processamento de BIG DATA (Spark, Hadoop, Flink, entre outras) e alguma ferramenta de orquestração das atividades envolvidas( apache airflow, Oozie, etc).

No caso do DW os dados são consultados na bases dimensionais do mesmo. E no caso do DL como disseminar a informação? Podemos indexar esses dados numa ferramenta de busca como o Elastic, armazenar os dados em um banco de dados NoSQL, ou ainda, jogar os dados tratados sob o formato de arquivo, numa ferramenta do tipo DMS (CKAN).

Com os dados tratados, é possível disponibilizar a informação através de ferramentas de visualização do tipo Self Service BI (Tableau, Qlik, PowerBI, apache superset, KIBANA entre outras), mas aí é assunto para outro post. 

Inté!

sexta-feira, 5 de agosto de 2022

Processamento de dados em larga escala Spark

Introdução

Chegamos a um ponto que os tradicionais bancos relacionais já não está atendendo as demandas de análise de dados. Por que digo isso? Com a popularização da Internet, advento da IOT (Internet das coisas), o volume de dados produzidos, seja de forma estruturada, não estruturada ou semi estruturada cresceu exponencialmente. Com isso foram surgindo tecnologias para suprir essas necessidades do mercado, capazes de processar grandes volumes de dados de forma paralelizada, descentralizada e distribuída e o Spark é uma alternativa criada pela a indústria para realizar esse tipo de processamento.

A solução mais conhecida e amada pelos profissionais de engenharia de dados era o Hadoop, contudo as operações realizadas através dessa solução dependem muito de operações de IO, representando um dos grandes gargalos do desempenho dos bancos de dados. O Spark resolve isso evitando essas operações, mantendo os conjuntos de dados em memória principal.

O que é?

O SPARK é um framework de código aberto para computação distribuída. Trata-se de um mecanismo que possibilita o processamento (análise) de grande volume de dados. Podemos entender a computação distribuída como um sistema que interliga vários computadores, conseguindo-se assim um grande poder de processamento. Esse conjunto de computadores é conhecido como CLUSTER e cada computador que faz parte desse conjunto é chamado de NÓ. Esse poder de processamento se torna mais eficiente se cada nó faz parte do trabalho. No Spark utiliza-se a estratégia DIVIDIR PARA CONQUISTAR.

Exemplificando, vamos supor que você tenha a tarefa de contar o número de M & M contidas em um pote. Você poderia contar sozinho (que daria muito trabalho) ou pedir ajuda de uns amigos para ajudar na contagem facilitando o trabalho. A atividade seria dividir os M & M's contidos no pote entre os amigos. Cada amigo contaria os M & M's que estão com eles e no final, você somaria as quantidades contabilizadas por você e pelos seus amigos para chegar ao resultado final. Essa é a estratégia adotada pelo Spark.

O Spark faz a divisão do conjuntos de dados, distribuindo os mesmos em estruturas conhecidas como  RDD's(Resilient, Distributed, Dataset).que ficam em memória principal e são imutáveis. A cada novo processamento, novos RDD's são criados de modo a refinar o processamento para no final, o resultado pro processamento ser gravado em disco.

Spark Core é o mecanismo de execução geral da plataforma Spark sobre o qual todas as outras funcionalidades são construídas. O Spark suporta desenvolvimento em várias linguagens como Java, Scala, Python, R e SQL. Além disso existem vários módulos dedicados a diferentes tipos de aplicação, como por exemplo SparkSQL que dá suporte escrever em linguagem SQL em vez de usar a api do Spark. Tem uma módulo chamado Spark Streaming que dá suporte a processamento de dados em tempo real. Tem a biblioteca de machine learning chamada SparkML com diversos modelos para serem utilizados, além de uma mecanismo para computação Gráfica chamada GraphX. Todo esse ecossistema contribuiu para o seu crescimento acelerado e ajudou o Spark a ser um dos sistemas de processamento massivo paralelo mais usados na área de Big Data.

No caso do Python, para interagir com o Spark é utilizada uma  biblioteca chamada PySpark.

Glossário do Spark

RDD (Resilient Distributed Datasets)- É a principal estrutura de dados do Spark. Um RDD é uma coleção de elementos particionada e imutável , o que significa que contém valores, e esses elementos são particionados para serem utilizados em sistemas distribuídos e não podem ser alterados. Não possuem uma estrutura de colunas e sim de linhas e exibidos como se fossem uma lista.

Spark Dataframe - Tem todas as características do RDD porém os dados estão organizados em colunas como uma tabela em um banco de dados. Foi estruturado para tornar mais fácil o processamento de grandes quantidade de dados. Apesar de estruturalmente serem diferentes, para quem conhece a estrutura de um dataframe da biblioteca de Pandas, a manipulação se torna mais fácil e por este motivo é a melhor escolha para começar a usar o PySpark. Existem algumas mudanças sutis entre o Spark dataframe e o Spark dataset que falaremos a seguir, mas o importante a saber quando estiver usando o Dataframe , estará aproveitando o formato interno otimizado pelo Spark e este formato aplica ganho de eficiência em todas as linguagens usadas pelas API's.

Spark Dataset - Eles são semelhantes aos DataFrames, mas são fortemente tipados, o que significa que o tipo é especificado na criação do DataSet e não é inferido o tipo de registros armazenados nele. Os Datasets estão disponíveis apenas para o Java Virtual Machine baseado nas linguagens Java e Scala e nele você define o tipo de dados que serão inseridos no Dataset.

Transformações- são as operações que podemos fazer em um DataFrame no Spark. É importante observar que as transformações criam novos RDDs porque, lembre-se, os RDDs são imutáveis, portanto, não podem ser alterados de depois de criados. Então as Transformações pegam um RDD como uma entrada e executam alguma operação e gera um ou mais RDDs. 

Como o Spark trabalha com Lazy evaluation , conforme um compilador verifica cada transformação, ele não cria nenhum RDDs novo, mas sim uma cadeia de RDDs e os resultados dessas transformações que são armazenados no DAG ,que só serão avaliadas uma vez quando uma uma Ação é chamado. Essa cadeia de RDDs ou “filhos”, todos conectados logicamente ao RDD “pai” , é chamado de gráfico de linhagem

Ações - uma ação é qualquer operação RDD que não produz um RDD como saída. Alguns exemplos de ações comuns são fazer uma contagem dos dados, máximo ou mínimo, retornar o primeiro elemento de um RDD, etc. Como foi mencionado antes, uma ação é a mensagem para o compilador avaliar o gráfico de linhagem e retorna o valor especificado pela ação.

Gráfico de linhagem - Um gráfico de linhagem descreve o que é chamado de “plano de execução lógico”. O que isso significa é que o compilador começa com os primeiros RDDs que não dependem de nenhum outro RDD e segue uma cadeia lógica de transformações até terminar com o RDD em que uma ação é chamada. Esse recurso é principalmente o que impulsiona a tolerância a falhas do Spark. Se um nó falhar por algum motivo, todas as informações sobre o que esse nó deveria estar fazendo são armazenadas no gráfico de linhagem, que pode ser replicado em outro lugar.

 Como o Spark executa uma tarefa

Você que é engenheiro de dados acabou de codificar um programa para ser executado no Spark. 

Ao colocar seu programa para executar, ele será executado como conjunto independente de processos em um cluster, coordenados por um programa principal (chamado de driver ).

Especificamente, para ser executado em um cluster, o driver pode se conectar a vários tipos de gerenciadores de cluster (seja o gerenciador de cluster do Spark, Mesos ou YARN), que alocam recursos para o seu programa. 

Uma vez conectado, o Spark adquire executores em nós no cluster, que na verdade são processos  ficam aguardando receberem uma ordem do driver para executar cálculos e armazenam dados para seu programa. Em seguida, o Spark envia o código do seu programa para os executores. Finalmente, o driver envia tarefas para os executores executarem.

Cada programa obtém seus próprios processos executores, que permanecem ativos durante todo o programa e executam tarefas em vários threads.

O driver deve escutar e aceitar conexões de entrada de seus executores ao longo de sua vida útil e como o driver agenda tarefas no cluster, ele deve ser executado próximo aos nós de trabalho, de preferência na mesma rede local.

É importante frisar que o Spark é um dos engines de big data mantidos pela a Apache Foundation Existem outros! Hadoop, Flink, Storm, Samza.

Gostou do post? Falaremos de outras soluções de processo aqui no blog.

domingo, 24 de julho de 2022

Processo de construção de um DW

Fiz uma série de posts falando sobre BI, onde falei de conceitos e ferramentas relacionadas ao assunto. Contudo, senti falta de falar sobre o processo de construção de DW e sobre as atividades envolvidas nesse processo.

Entendo que o primeiro passo é entender o que o cliente quer, definindo quais métricas e quais descritores ele quer analisar.

Definido o objeto de estudo, é importante buscar nos sistemas transacionais, os insumos para  compor o DW e verificar a forma que estes dados serão extraídos.

Com os dados em mãos, partimos para higienização dos mesmos. Neste caso, importa-se esses dados para uma área que chamados de stage, aonde realizamos transformações e enriquecimentos. Nesta hora, o auxílio de uma ferramenta de ETL ajuda bastante.

Após o tratamento dos dados, partimos para a modelagem dimensional, onde criamos as dimensões e os fatos que comporão o DW.

Feito isso, é preciso montar uma estratégia para realizar a carga das tabelas criadas. Mais uma vez uma ferramenta de ETL ou até mesmo, scripts nos ajudarão nesta tarefa.


Segue abaixo as atividades envolvidas no processo. 


DW pronto, é importante encontrar uma boa ferramenta de visualização de dados para permitir a análise dos dados.

De forma resumida é isso.

Inté!

segunda-feira, 27 de junho de 2022

Programação orientada a objetos na prática

A Programação estruturada (PE) foi o paradigma dominante na escrita de software até a chegada da programação orientada a objetos (POO). Enquanto a PE fia-se em estruturas de controle e repetição, a POO se baseia no conceito de objetos que possuem atributos (dados) e métodos (procedimentos).

Geralmente as pessoas que começaram a programar estruturado tem dificuldade de entender como programar orientado a objetos. Vejamos se eu consigo desmistificar isso através de comparações de código.

Vamos ao código estruturado

<?php  
$nome = 'Fulano';
$salarioBase = 1000;
$horasExtras = 10;
$valorDaHoraExtra = 20;

$salrioEfetivo = $salarioBase + ($horasExtras * $valorDaHoraExtra);

Uma versão orientada a objetos seria

<?php
require 'Funcionario.php';

$funcionario = new Funcionario();

$funcionario->setNome('Fulano');
$salarioBase->setSalarioBase(1000);
$horasExtras->setHorasExtras(10);
$valorDaHoraExtra->setValorDaHoraExtra(20);
echo $funcionario->getSalarioEfetivo();

Repare que toda a lógica de programação passou a ficar na classe e não no código fonte do programa principal.

<?php
class Funcionario(){
    private $nome;
    private $salarioBase;
    private $horasExtras;
    private $valorDaHoraExtra;

    public function setNome($nome){
        $this->nome = $nome;
    }
    public function setSalarioBase($valor){
        $this->$salarioBase = $valor;
    }
    public function setHorasExtras($valor){
        $this->$horasExtras = $valor;
    }
    public function setValorDaHoraExtra($valor){
        $this->$horasExtras = $valor;
    }
    public getSalarioEfetivo(){
        return $this->salarioBase + ($this->horasExtras * $this->valorHoraExtra);
    }


}

A vantagem disso é impedir ao programador a cometer erros, facilitar a manutenção,  visto que o código fica mais inteligível. 

Com a criação de classes é possível fazer o reuso de código.

Mas se você pensa que parou por aí, não sabe de nada inocente. Conhecer os conceitos de encapsulamento, herança, polimorfismo e ainda conhecer designer paterns é essencial para programar orientado a objetos. Caso queira dar uma olhadinha nesses conceitos sugiro a você ler um post que escrevi a milênios antes de cristo.

sábado, 25 de junho de 2022

O VBScript

VBScript é uma linguagem de criação de Scripts, a qual é derivada do Visual Basic (VB) e do VBA (Visual Basic for Applications). A ideia deste Post é ensinar o VBScript para rodar scripts no lado servidor utilizando a tecnologia ASP 3.0.

Abaixo é apresentado um resumo da linguagem, materializado através de uma página ASP. Em outros post vamos falar sobre os objetos da ASP.DLL

<%
'ASP é uma ferramenta antiga (mas ainda poderosa) para criar páginas da Web dinâmicas.

'ASP é uma tecnologia (muito parecida com PHP) para executar scripts em um
'servidor web.
%>
<!DOCTYPE html>
<html lang="pt-br">
  <head>
    <title>Resumo VBSCRIPT</title>
    <meta charset="utf-8">
  </head>
  <body>
<%
'utilize Option Explicit para forçar a declaração de variáveis
'Option Explicit
'variáveis utilize o comando dim para declarar variáveis
Dim x,y,z
x = 20
y = 10
z = 5
Dim nome
nome = "Hugo"
'O VB utiliza um tipo de dados conhecido como Variante que possui os seguintes
'subtipos
'Subtipo -  Descrição
'Empty   -  O Valor é zero para variáveis numéricas ou uma String de tamanho zero
'(“ “), para variáveis de texto.
'Null    - A variável não contém dados válidos.
'Boolean - Contém variáveis que somente podem assumir dois valores: Verdadeiro ou
'Falso (True ou False).
'Byte    -  Valor inteiro, na faixa de 0 até 255.
'Integer - Valor inteiro, na faixa de -32768 até 32767.
'Currency   - Valores na faixa de –923.337.203.685.447,5808
'até 922.337.203.685.447,5807
'Long     - Valor inteiro, na faixa de –2.147.483.648 até 2.147.483.647.
'Date/Time  - É um número que representa a data entre 01 de Janeiro do ano 100,
' até 31 de Dezembro de 9999 (Olha o bug do ano 2000 chegando).
'String     - Texto de tamanho variável, pode conter, aproximadamente,
' 2 bilhões de caracteres.
'Object     - Pode conter um objeto qualquer, como um Controle Activex,
'ou um Objeto COM+
'Error      - Pode conter um número de erro.

'operadores aritméticos

'Operador   Símbolo  Descrição
'Adição  +  Soma o valor de duas ou mais variáveis.
'Subtração  -  Subtração entre duas ou mais variáveis.
'Multiplicação *  Multiplica os valores de duas ou mais variáveis.
'Divisão /  Divide o valor de duas ou mais variáveis.
'Inteiro da divisão  \  Retorna a parte inteira da divisão entre dois números
'Exponenciação ^  x^y -> É o valor do número x, elevado na potência y.
'Módulo  mod   Retorna o resto de uma divisão de 2 números.

Dim som, subtr, divis, mult, intdivs, expo, modul

som = x + y
subtr = x - y
divis = x / y
mult = x * y
intdivs =  x \ y
expo = x ^ y
modul = x mod y
response.write(nome & "<br>")
response.write ("A soma de x e Y é igual a " & som & "<br>")

'Operador   Símbolo  Descrição
'Igualdade  =  É igual a.
'Desigualdade  <> É diferente de.
'Maior que  >  É maior do que.
'Menor que  <  É menor do que.
'Maior ou igual   <= É maior ou igual a.
'Menor ou igual   >= É menor ou igual a.

response.write("X" & " é igual a " & y & "? " & X = y & "<br>")

'Estruturas de condição
If x > y Then
  response.write ("X é maior que é Y" & "<br>")
else
  response.write("X não é maior que Y" & "<br>")

End if

y = 20

if x > y then
   response.write ("X é maior que é Y" & "<br>")
elseif x = y then
   response.write ("X é igual a Y" & "<br>")
elseif x < y then
   response.write ("X é menor a Y" & "<br>")
else
    response.write ("X  é  diferente Y" & "<br>")
end if

select case y
case 10
 
   response.write ("y é igual a 10" & "<br>")
case 15
   
   response.write ("y é igual a 15" & "<br>")
case else
   
   response.write ("Não sei o valor de Y" & "<br>")

end select

'Estruturas de repetição


for i = 0 to z
 
   response.write (i & "<br>")
next

For i=0 to x  Step 2
 response.write (i & "<br>")
next
dim contador
contador = 0
do While contador < z
   response.write(contador & "<br>")
   contador = contador + 1
loop
 contador = 0
 DO
  response.write(contador & "<br>")
  contador = contador + 1
 Loop While contador < z
contador  = 0
 do until contador < z
 response.write(contador & "<br>")
 loop
 'Funções e Procedimentos criados pelo usuário
Function CDolar(valor)
           CDolar = (valor * 5)
End Function

Response.write(CDolar(10) & "<br>")
'procedimentos
sub escreve_nome(nome)

     response.write(nome)

end sub

Call escreve_nome("Rogério")

'ou
response.write("<br>")

escreve_nome("Habbema")

'funções da linguagem

response.write(Asc(“Ainda chovia”) & "<br>")

' ver referência em http://msdn.microsoft.com/scripting

%>
  </body>
</html>

ACTIVE SERVER PAGES (ASP)

Definição.

O ASP (de Active Server Pages), também conhecido como ASP Clássico hoje em dia, é uma estrutura de bibliotecas básicas (e não uma linguagem) para processamento de linguagens de script no lado servidor para geração de conteúdo dinâmico na Web. Exemplos de linguagens aceitas são: VBScript, JScript, PerlScript, Tcl ou Python sendo que apenas as duas primeiras são suportadas por padrão.[1], Sendo o VBScript, a linguagem de script mais utilizada pelos programadores que utilizavam essa tecnologia.

Apesar do ASP ter sido substituído pelo ASP.NET, até hoje é suportada por versões atuais do IIS e a meu ver, a Microsoft não a substituição por conta dela não ter dado certo. Ainda hoje, existem sistemas que utilizam essa tecnologia no ar.

Ele roda nativamente em Windows, através do serviço chamado de IIS (Internet Information Service) - o servidor web da Microsoft. Além disso ele pode rodar em outras plataformas, como Linux no servidor Apache quando usando um módulo de um programa como o Tomcat.

O processo


Basicamente é feita uma requisição a uma página com a extensão .ASP. O servidor ao receber essa requisição, passa o código para que uma DLL (ASP.DLL) realize o processamento do código de script presente nesta página e retorna o resultado deste processamento ao servidor. O servidor então devolve esse resultado ao navegador que fez a requisição, em formato HTML, XML, TXT.

ASP DLL

Essa DLL nos dá acesso a uma série de objetos e métodos que fornecem diversas funcionalidades necessárias à criação de páginas dinâmicas. Como exemplo, temos um objeto chamado Request, o qual pode ser utilizado para processar as informações que o usuário preenche em um formulário. Temos também um objeto Response, do qual já utilizamos o método Write, o qual é utilizado para retornar informações para o Navegador do cliente, e assim por diante.



O modelo de Objetos do ASP 3.0, apresenta os seguintes objetos:

Response - Utilizamos o Objeto Response para retornar o resultado do processamento de uma página ASP, para o Navegador do cliente. O resultado retornado é código HTML puro. Podemos utilizar o objeto Response para montar uma página de retorno, por exemplo, com os resultados de uma pesquisa em um Banco de Dados.Também podemos utilizar o Objeto Response para gravar Cookies no computador do Cliente.

Request - Com o Objeto Request podemos ter acesso a diversas informações fornecidas pelo cliente ao acessar uma página ASP, ou ao preencher um formulário e enviar os dados do formulário. Podemos ter acesso a informações a respeito do Navegador que o cliente está utilizando, quais os Cookies gravados no computador do usuário, qual Certificado Digital o usuário está utilizando e muitas outras informações importantes.

Application - podemos utilizar o objeto Application para compartilhar informações entre todos os usuários de um determinado aplicativo. Um aplicativo Web baseado no ASP é definido como todos os arquivos .asp em uma pasta virtual e seus subdiretórios. Como o objeto Application pode ser compartilhado por mais de um usuário, existem os métodos Lock e Unlock para garantir que vários usuários não tentarão alterar uma propriedade ao mesmo tempo.

Session Podemos usar o objeto Session para armazenar as informações necessárias para uma determinada sessão de usuário. As variáveis armazenadas no objeto Session não são descartadas quando o usuário alterna entre as páginas do aplicativo; em vez disso, essas variáveis persistem durante toda a sessão de usuário.

Server - O objeto Server nos fornece a possibilidade de estender as capacidades de nossas páginas ASP, através da utilização de objetos e componentes externos. Estes objetos e componentes fornecem funcionalidades específicas as quais são necessárias à aplicação que está sendo desenvolvida.

A utilização de componentes externos faz parte da filosofia de desenvolvimento de aplicações baseadas em componentes. Para o mundo Windows, os componentes devem seguir o padrão COM (Component Object Model) que no Windows 2000 recebe a denominação de COM+ (COM Plus).

Exemplo de componentes bastante utilizados são ADO, FileSystemObject e o CDONTS.

Um objeto pode conter propriedades, coleções, métodos e eventos.

Propriedades - característica ou atributo de um objeto.

Exemplo: Ao setarmos a propriedade ScriptTimeout do objeto Server,  definimos quanto  tempo  o código ASP pode ficar executando em uma página, antes que o Servidor cancele a execução e retorne uma mensagem de erro.

métodos - comportamento ou ação realizada por um objeto.

Exemplo: Ao chamar o método Write do objeto Response (Response.Write), o comportamento esperado é que o método Write envie o texto fornecido entre aspas, para o servidor Web, o qual por sua vez envia para o Navegador do cliente.

coleções - conjunto de valores do objeto que podem ser acessados via código.

Exemplo: A coleção Form, do objeto Request, contém os nomes e valores de todos os controles de um formulário cujos dados foram passados para processamento da página ASP.

eventos -  é uma determinada ação que pode acontecer, e para a qual podemos escrever código ASP em resposta ao evento.

Exemplo: o Objeto Session possui um evento OnStart, o qual ocorre quando uma usuário estabelece uma seção com uma página ASP e antes que uma requisição do usuário seja executada. Podemos utilizar este evento para iniciar variáveis ou rodar qualquer outro código que seja necessário. Você já deve ter entrado em um site onde é necessário preencher um formulário de cadastramento. Da próxima vez que você entra no site, você recebe uma mensagem dizendo “Bem vindo Fulano de tal!”. Como é que o site sabe que é você, ou pelo menos o seu computador, que está entrando no site? A página utiliza o evento Session.OnStart, para ler informações que foram gravadas no seu computador, normalmente na forma de um Cockie e determinar quem está acessando a página. 

Bom pessoal, a ideia deste post foi dar um overview de como essa tecnologia funciona. Em outro post, vamos detalhar os objetos do ASP e dar exemplos práticos.

Inté.

quinta-feira, 16 de junho de 2022

O que são Frameworks?

Você quer se tornar um desenvolvedor Web e fica se perguntando o que precisa aprender para trabalhar nesse área. Aquele colega que você que você coloca no pedestal lhe fala que você precisa aprender REACT, BOOTSTRAP, JQUERY, NODEJS, ASP.NET entre outras coisas. Daí você pergunta pro colega o que é aquela sopa de letrinhas e fica sem saber por onde começar. O colega explica que se tratam de FRAMEWORKS utilizados no dia a dia do programador WEB e aí se instaura uma confusão na sua cabeça.
Mas que diabos é FRAMEWORK e por qual deles começar a estudar? E aquele colega responde: É o cinto de utilidades do programador web e você continua sem entender não é isso?

Vou tentar explicar. Digamos que você queira desenvolver um sistema WEB do zero, ou seja, escrever da primeira até a última linha de código do mesmo. Isso daria muito trabalho. Agora vamos imaginar em fazer isso através do reúso de código feito por outras pessoas. Concorda que se fizéssemos dessa forma, economizaríamos tempo?

FRAMEWORS  são bibliotecas de códigos escritos por outras pessoas que podem ser reutilizados para a criação de aplicativos ou sistemas.

Tudo bem. Mas código escrito em quê? Depende de qual framework estamos falando? Você quer estilizar uma página HTML? Utilize o Bootstrap que é uma biblioteca de classes CSS. Quer utilizar Javascript nas suas páginas? JQUERY ainda é muito utilizado pra isso, mas tem perdido popularidade para tecnologias do tipo SPA (REACT, Angular, Vue, entre outras).

Quem não utiliza o JDK ao desenvolver um sistema feito em JAVA ou o .NET Framework ao desenvolver sistemas feitos em ASP.NET?

Ficou faltando responder a pergunta do colega: Por qual delas começar? É importante conhecer a linguagem base desses frameworks. Vai mexer com desenvolvimento WEB? Estude HTML, CSS, Javascript, antes de mexer com um Framework.

Será que fui claro?

Abraço!


terça-feira, 14 de junho de 2022

O protocolo HTTP

     Quando abrimos um navegador, digitamos uma URL na barra de endereço e damos um ENTER, o navegador (O CLIENTE) faz uma requisição para um recurso hospedado em um servidor. O SERVIDOR então devolve para o cliente o recurso requisitado (páginas html, scripts PHP, ASP, JSP, arquivos css, arquivos js, imagens, e documentos de diversas espécies, .DOC.XLS,PDF, XML, JSON,entre outros). 

Essa resposta é uma espécie de pacote composto por dados e por um código de STATUS. Esse código serve para indicar para o cliente, a situação da resposta dada pelo servidor. Se o recurso requisitado foi enviado com sucesso ou não, seja por não ter encontrado o recurso requisitado, seja por conta de alguma problema que o servidor requisitado tenha enfrentado. Toda essa troca de informação é feita por meio do protocolo HTTP.

 HTTP é um protocolo (protocol) que permite a obtenção de recursos, como documentos HTML. É a base de qualquer troca de dados na Web e um protocolo cliente-servidor, o que significa que as requisições são iniciadas pelo destinatário, geralmente um navegador da Web. Um documento completo é reconstruído a partir dos diferentes sub-documentos obtidos, como por exemplo texto, descrição do layout, imagens, vídeos, scripts e muito mais.

Os códigos de status do HTTP são representados por 5 grupos de numeração. São eles

  • 100 a 199 - status de informação
  • 200 a 299 - status de sucesso (200 OK)
  • 300 a 399 - status de redirecionamento
  • 400 a 499 - status de erro de cliente (404 página não encontrada)
  • 500 a 599 - status de erro de servidor (500 erro no servidor)
Algo muito comum hoje em dia é a requisição a uma API (application programing Interface). Trata-se de um recurso que pode ter diversas funcionalidades que são retornadas em formato XML ou formato JSON. Para requisitar esses recursos, é necessário conhecer o endereço que é a URL(Uniforme Resource Locator) desse recurso. 

Esse endereço é composto pelo tipo de protocolo(http://), mais o IP do servidor (127.0.0.1) e a porta que está sendo utilizada (:5094).

É importante também se conhecer o nome do recurso que é chamado de URN (Uniforme Resource Name).

A junção da URL com a URN é conhecida com URI (Universal Resource Identifier).

Exemplo: http://127.0.0.1:3000/clientes

Sabendo disso, nos resta fazer as requisições de forma padronizada e é aí que entra o conceito de REST (Representational State Transfer).

A requisição é feita por meio de métodos do protocolo HTTP. São eles:

  • GET (quando se quer buscar alguma informação)
  • POST (quando se quer registrar alguma informação no servidor)
  • PUT (quando se quer alterar alguma informação registrada no servidor)
  • DELETE (quando se quer excluir alguma informação registrada no servidor)
Bom, vamos parar de papo furado e colocar a mão na massa. Para isso, vamos fazer uso do  CURL.

O que é o curl

Curl é uma ferramenta para transferir dados de/para um servidor, usando um dos protocolos suportados. Normalmente estamos usando o HTTP.

Ele é uma ferramenta de linha de comando que funciona como interface para a biblioteca que faz o serviço pesado, o libcurl.

De forma geral, seu navegador realiza requisições web, recebe respostas, lê/escreve cookies e renderiza sua página. O curl pode fazer tudo isso, exceto a renderização, que cabe ao seu navegador.

Ele oferece uma infinidade de funções úteis como realização de autenticação, interação com API's, preencher formulários HTML, download de arquivos e paginas HTML etc.

Desde de a versão 10 o CURL já vem instalado no windows.

Abra o prompt do windows e digite curl www.google.com/

A resposta será o código HTML da página inicial do google.

Também é possível obter uma resposta mais verbosa, permitindo visualizar os cabeçalhos da requisição HTTP usando a opção -i. Executando o comando abaixo você poderá vizualizar informações como o Status Code da resposta, a data e hora em que ela foi enviada, o tipo do conteúdo da resposta e várias outras informações que podem variar a depender da implementação do servidor.

curl -i http://www.google.com/

A primeira linha indica a versão do protocolo HTTP usada e o Status Code de sucesso (200).

Caso queira ignorar o conteúdo da página e receber somente o cabeçalho, você pode usar a opção -I (i maiúsculo).

curl -I https://www.google.com/

Fazendo download de arquivos:

Vamos utilizar aqui a mídia de instalação da ultima versão do Ubuntu como exemplo. Para fazer o download de um arquivo, salvando com o mesmo nome do arquivo definido pelo servidor, basta usar a opção -O.

curl-O https://releases.ubuntu.com/20.04.1/ubuntu-20.04.1-desktop-amd64.iso

Interagindo com API's REST com GET e POST

O curl também é útil para realizar testes de API's REST. Tomemos como exemplo a aplicação https://jsonplaceholder.typicode.com/ que foi feita justamente para fins de testes.

Ela possui as seguintes rotas:

GET /posts
GET /posts/:id
GET /posts/:id/comments
GET /comments?postId={:id}
POST /posts
PUT /posts/:id
PATCH /posts/:id
DELETE /posts/:id

Por padrão, o curl usa o método HTTP GET para realizar as requisições. Para fazer uma requisição GET, basta executar

curl https://jsonplaceholder.typicode.com/posts

O retorno será em formato JSON contendo uma lista de posts:

[ { "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum
rerum est autem sunt rem eveniet architecto" }, { "userId": 1, "id": 2, "title": "qui est esse", "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate
porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" }, { "userId": 1, "id": 3, "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis
pariatur\nmolestiae porro eius odio et labore et velit aut" }, [continua ...]

Também é possível especificar qual método usar, passando a opção -X e o método como argumento:

curl -X GET https://jsonplaceholder.typicode.com/posts

Para realizar a criação de um post, você pode executar:

curl -i -X POST https://jsonplaceholder.typicode.com/comments \ -H 'Content-Type: application/json' \ -d $'{ "postId": 101, "name": "Vitor Almeida", "email": "vitor.almeida@alura.com.br", "body": "De acordo ao manual do curl ( disponível online [...]" }'

Resultando em

HTTP/2 201 date: Tue, 05 Jan 2021 01:17:53 GMT content-type: application/json; charset=utf-8 content-length: 168 set-cookie: __cfduid=d4f15935c351e1b9ece6e8d8cdb1ffa1a1609809470; expires=Thu, 04-Feb-21 01:17:50 GMT;
path=/; domain=.typicode.com; HttpOnly; SameSite=Lax x-powered-by: Express [continua ...] { "postId": 101, "name": "Vitor Almeida", "email": "vitor.almeida@alura.com.br", "body": "De acordo ao manual do curl ( disponível online [...]", "id": 501 }

A opção -H permite adicionar um cabeçalho e a -d permite passar os dados da requisição. Nesse caso, definimos que o conteúdo é no formato JSON e passamos o conteúdo da requisição que será usado para criar uma conta. Podemos ver no resultado que o status foi 201, indicando que um novo recurso foi criado.

Uma alternativa ao CURL é um cara chamado POSTMAN, mas uma coisa de cada vez. Um dia faço um POST sobre o assunto.

Até a próxima!