[{"content":"Em um post anterior eu comentei sobre a importância do operador módulo e como ele pode, além de simplesmente dar o resto da divisão, também ajudar a criar ciclos numéricos, muito úteis quando precisamos seguir uma sequência numérica em que, ao chegar no final, a contagem reinicia.\nx % 5: sobe até o limite e reinicia O limite do módulo A abordagem é totalmente funcional, mas tem uma limitação na forma do ciclo: o módulo sobe em linha reta e, ao chegar no limite, cai bruscamente de volta ao zero, formando uma onda \u0026ldquo;dente de serra\u0026rdquo;. Se você precisar de algo que suba e desça suavemente, passando por valores intermediários nos dois sentidos, o módulo não resolve, pois ele nunca \u0026ldquo;volta\u0026rdquo; de forma gradual, só reinicia.\nSeno e cosseno Neste ponto, para nos ajudar, encontramos as funções periódicas, sendo as famigeradas funções seno e cosseno as principais candidatas. Daqui pra frente vamos trabalhar apenas com a função seno, mas saiba que tudo deste post se aplica a ambas, com a diferença de que a função cosseno está adiantada noventa graus em relação à função seno (mais tarde explico isso também).\nA primeira coisa que precisamos definir é que a função sin(x) tem sua imagem, ou seja, o conjunto de resultados possíveis, no intervalo [−1,1]: ela fica subindo e descendo entre esses dois valores. Outro detalhe importante é que o seno trabalha em radianos, e não em graus: uma volta completa, os 360°, equivale a 2π≈6,28 radianos. Por isso, no gráfico abaixo, a onda leva 2π unidades no eixo X para completar um ciclo.\nSeno em um ciclo completo Amplitude: a altura da onda Neste momento pode surgir uma dúvida: como algo que só varia entre -1 e 1 pode ser útil para mim? A resposta é simples: quando precisarmos que ela varie entre números maiores, podemos simplesmente multiplicá-la por um valor que consideremos nosso limite. Aqui vamos chamar esse valor de A e teremos A⋅sin(x). Considerando A igual a 5, temos o gráfico a seguir:\nVariando entre -5 e 5 O que esse A representa é uma grandeza chamada amplitude, ou seja, quanto a onda se afasta, para cima e para baixo, da sua linha central (por enquanto o eixo X, mas isso vai mudar daqui a pouco). Como amplitude é uma medida de distância, e distância negativa não existe, definimos formalmente como amplitude=∣A∣. Um A negativo apenas espelha a onda, deixando-a de cabeça para baixo.\nPeríodo: o tamanho do ciclo Agora finalmente temos uma função mais útil, variando até qualquer valor que eu deseje, mas entra uma nova questão: estamos presos num ciclo de tamanho fixo, ou seja, a onda sempre leva a mesma distância no eixo X para subir, descer e voltar ao ponto de partida, que no nosso caso é 2π. A essa distância damos o nome de período, comumente representado por T.\nAqui as coisas ficam divertidas, pois podemos controlar o período multiplicando o x por um valor dentro da função seno. Esse valor é chamado de frequência angular e costuma ser representado pela letra grega ω (ômega):\nA⋅sin(ωx)Mas por que isso muda o período? O seno completa um ciclo quando o seu argumento vai de 0 até 2π. Como agora o argumento é ωx, o ciclo se completa quando ωx=2π, ou seja, quando x=ω2π​. Esse é o nosso novo período:\nT=∣ω∣2π​O ω pode ser qualquer número diferente de zero; se for negativo, a onda apenas fica espelhada, e por isso a fórmula usa o valor absoluto. Perceba que, quanto maior o ω, mais rápido o argumento chega em 2π e menor fica o período.\nNa prática, porém, geralmente sabemos qual período queremos e precisamos descobrir o ω. Para isso basta isolá-lo na fórmula acima (considerando ω positivo):\nω=T2π​Se quisermos, por exemplo, que o período seja de 1 unidade no eixo X, temos ω=12π​=2π, e a nossa função fica 5⋅sin(2πx):\nCompleta o ciclo a cada 1 unidade Já para um ciclo completo a cada 5 unidades, é só trocar o T: ω=52π​, e a função fica:\n5⋅sin(52π​x)Olhando no gráfico, podemos verificar o ocorrido:\nAgora a função completa o ciclo em 5 unidades Um pequeno parêntese sobre o nome: a frequência \u0026ldquo;comum\u0026rdquo;, f=T1​, diz quantos ciclos acontecem a cada unidade do eixo X. A frequência angular é essa mesma ideia medida em radianos, ou seja, ω=2πf.\nLinha central: subindo e descendo a onda Perceba que a variação ainda vai de um valor negativo até esse mesmo valor positivo, mas pode ser que precisemos que ela ocorra mais acima ou mais abaixo. Para isso, vamos introduzir um novo parâmetro na nossa equação, o deslocamento vertical=B, que permitirá deslocar a onda para cima e para baixo. Isso é bem simples: basta somar B ao que temos até agora:\nA⋅sin(ωx)+BDesta forma, agora toda a onda é deslocada em B unidades. Se, por exemplo, definirmos B como 10, nosso gráfico se deslocará 10 unidades para cima, com a linha central agora em 10, não mais iniciando no zero nem tocando o eixo X:\nAgora a onda oscila entre 5 e 15, em torno de 10 Exemplo: a temperatura ao longo do ano Apenas com estes três parâmetros podemos, por exemplo, modelar alguns probleminhas simples: vamos supor que, num ciclo de 365 dias, a temperatura de uma cidade, em Celsius, começa em 20 graus na primavera, atinge um pico de 30 graus no verão, volta aos 20 graus no outono e chega a 10 graus no inverno. Isolando cada valor, podemos chegar a algumas conclusões:\nA temperatura oscila entre 10 e 30 graus, então sua linha central é a média dos dois, 230+10​=20, e esse é o nosso deslocamento vertical B=20. (Como o seno começa justamente na linha central, isso bate com os 20 graus do início do ciclo.) A partir da linha central, a temperatura sobe ou desce no máximo 10 graus, assim sabemos que esse é o nosso A=10. Ele também pode ser calculado como metade da distância entre o máximo e o mínimo, 230−10​=10. O ciclo completo de medições é de 365 dias, ou seja, nosso período é T=365, logo ω=3652π​. As duas primeiras contas valem para qualquer onda da qual você conheça o máximo e o mínimo:\nB=2max+min​A=2max−min​E chegamos à nossa função final:\n10⋅sin(3652π​x)+20E o nosso gráfico de temperatura fica:\nA variação de temperatura durante o ano Neste modelo simples já é possível ter uma noção de como a temperatura varia no decorrer do ano, seus máximos e mínimos e, principalmente, os valores intermediários. É claro que um modelo real é muito mais complexo, mas, para a compreensão básica, isso já ajuda a entender o poder das funções periódicas.\nFase: deslocando a onda no tempo Mas vamos enriquecer o nosso problema com mais uma restrição: no modelo acima, o dia 0 é o início da primavera, mas, como aqui no Brasil o verão é em janeiro, queremos que o dia 0 seja o início do ano, já no pico da temperatura. Hoje esse pico está no dia 4365​, então precisamos deslocar a função 41​ de ano para trás. Temos como controlar isso através do deslocamento de fase=φ (a letra grega fi), que é somado ao argumento da função seno:\nA⋅sin(ωx+φ)+BPara entender o efeito do φ, basta colocar o ω em evidência:\nsin(ωx+φ)=sin(ω(x+ωφ​))Somar ωφ​ ao x faz a função mostrar agora o que só mostraria mais adiante: no dia 0 ela já vale o que antes valia no dia ωφ​. Ou seja, a onda inteira é deslocada ωφ​ unidades para a esquerda. Usando a convenção de que valores positivos são deslocamentos para a direita, o número exato que será deslocado é:\ntotal deslocado=−ωφ​Assim, para trazer o pico para o dia zero, precisamos mover a curva um quarto de ano para a esquerda, ou seja, um deslocamento de −4365​. Podemos desenvolver:\n−4365​=−ωφ​φ=ω⋅4365​=3652π​⋅4365​=2π​​Se aplicarmos ao nosso modelo, temos:\n10⋅sin(3652π​x+2π​)+20 A variação de temperatura durante o ano iniciando no verão Por que o cosseno está adiantado E aqui cumpro a promessa do início do post: o deslocamento de fase que encontramos, φ=2π​, é justamente um quarto de volta, os tais noventa graus, e é exatamente a diferença entre seno e cosseno. Vale a identidade sin(x+2π​)=cos(x), então nossa função final pode ser escrita como 10⋅cos(3652π​x)+20.\nSeno e Cosseno lado a lado É isso que significa dizer que o cosseno está \u0026ldquo;adiantado\u0026rdquo; noventa graus: ele já começa no pico onde o seno só chega depois de um quarto de ciclo. Na prática, escolher seno ou cosseno é só uma questão de qual ponto do ciclo você quer no instante zero.\nJuntando tudo em código Para fechar, vamos voltar ao código. Juntando tudo o que vimos, podemos escrever uma função que gera qualquer uma dessas ondas e compará-la com o ciclo feito com o módulo no início do post:\nimport math def onda(x, amplitude, periodo, centro=0.0, fase=0.0): omega = 2 * math.pi / periodo return amplitude * math.sin(omega * x + fase) + centro for x in range(11): dente_de_serra = x % 5 suave = onda(x, amplitude=2, periodo=5, centro=2) print(f\u0026#34;{x:2}: {dente_de_serra} {suave:.2f}\u0026#34;) 0: 0 2.00 1: 1 3.90 2: 2 3.18 3: 3 0.82 4: 4 0.10 5: 0 2.00 6: 1 3.90 7: 2 3.18 8: 3 0.82 9: 4 0.10 10: 0 2.00 Os dois ciclos têm período 5 e ficam entre 0 e 4, mas enquanto o módulo sobe e despenca, a onda sobe e desce passando por todos os valores intermediários. E, como a função aceita qualquer número real, basta trocar o x pelo tempo decorrido para ter um botão pulsando na tela, um LED \u0026ldquo;respirando\u0026rdquo; ou um inimigo flutuando para cima e para baixo em um jogo.\nResumo dos parâmetros Para consulta rápida, um resumo dos parâmetros de A⋅sin(ωx+φ)+B:\nParâmetro O que controla Como calcular A quanto a onda sobe e desce 2max−min​ ω o período T2π​ φ o deslocamento horizontal −ω⋅deslocamento B a linha central 2max+min​ ","permalink":"https://blog.lucaspolo.dev/posts/criando-ciclos-a-maneira-abrangente/","summary":"\u003cp\u003eEm \u003ca href=\"https://blog.lucaspolo.dev/posts/usando-o-operador-de-modulo-para-criar-ciclos/\"\u003eum post anterior\u003c/a\u003e eu comentei sobre a importância do operador módulo e como ele pode, além de simplesmente dar o resto da divisão, também ajudar a criar ciclos numéricos, muito úteis quando precisamos seguir uma sequência numérica em que, ao chegar no final, a contagem reinicia.\u003c/p\u003e\n\u003cfigure class=\"function-plot-figure\"\u003e\n  \u003cdiv id=\"plot-0\" class=\"function-plot\" data-plot=\"{\u0026#34;data\u0026#34;:[{\u0026#34;fn\u0026#34;:\u0026#34;x % 5\u0026#34;}],\u0026#34;xAxis\u0026#34;:{\u0026#34;domain\u0026#34;:[0,20]},\u0026#34;yAxis\u0026#34;:{\u0026#34;domain\u0026#34;:[-1,6]}}\"\u003e\u003c/div\u003e\u003cfigcaption\u003ex % 5: sobe até o limite e reinicia\u003c/figcaption\u003e\u003c/figure\u003e\n\u003ch2 id=\"o-limite-do-módulo\"\u003eO limite do módulo\u003c/h2\u003e\n\u003cp\u003eA abordagem é totalmente funcional, mas tem uma limitação na forma do ciclo: o módulo sobe em linha reta e, ao chegar no limite, cai bruscamente de volta ao zero, formando uma onda \u0026ldquo;dente de serra\u0026rdquo;. Se você precisar de algo que suba e desça suavemente, passando por valores intermediários nos dois sentidos, o módulo não resolve, pois ele nunca \u0026ldquo;volta\u0026rdquo; de forma gradual, só reinicia.\u003c/p\u003e","title":"Criando ciclos - A maneira abrangente"},{"content":"Olá! Meu nome é Lucas, eu sou residente aqui do Brasil, radioamador, nerd e engenheiro de software. Gosto de ocasionalmente compartilhar o que estou aprendendo, principalmente para ajudar a consolidar os meus aprendizados.\nPara acompanhar o blog, assine o RSS ou navegue pelo arquivo com todos os posts. Meus projetos ficam no GitHub.\nSe precisar entrar em contato, mande um e-mail para contato [at] lucaspolo.dev\n","permalink":"https://blog.lucaspolo.dev/about/","summary":"\u003cp\u003eOlá! Meu nome é Lucas, eu sou residente aqui do Brasil, radioamador, nerd e engenheiro de software. Gosto de ocasionalmente compartilhar o que estou aprendendo, principalmente para ajudar a consolidar os meus aprendizados.\u003c/p\u003e\n\u003cp\u003ePara acompanhar o blog, assine o \u003ca href=\"/index.xml\"\u003eRSS\u003c/a\u003e ou navegue pelo \u003ca href=\"/archives/\"\u003earquivo com todos os posts\u003c/a\u003e. Meus projetos ficam no \u003ca href=\"https://github.com/lucaspolo\"\u003eGitHub\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eSe precisar entrar em contato, mande um e-mail para \u003ccode\u003econtato [at] lucaspolo.dev\u003c/code\u003e\u003c/p\u003e","title":"Sobre"},{"content":"A vida de estudante não é fácil, no meu tempo ainda tínhamos o custo da xerox mas hoje felizmente isso é passado e as coisas são digitais. Mas logo tudo isso se converte em custos na compra de equipamentos, sendo necessário pelo menos um tablet para conseguir frequentar as aulas, custo na aquisição de software e muitas outras coisas. Felizmente algumas empresas oferecem descontos e até produtos inteiramente grátis para estudantes, e eu que voltei a ser estudante, estou aproveitando isso melhor agora.\nNo geral, para ter acesso a estes descontos, é necessário que você tenha um e-mail da instituição, porém nem sempre a escola que você estuda oferece um, então algumas empresas aceitam um comprovante de matrícula, que pode ser obtido na secretária da sua faculdade.\nVamos para a lista de softwares, serviços e produtos em que é possível obter inteiramente ou parcialmente gratuitos. Lembrando que a licença fornecida na maioria dos casos é de uso apenas individual e para fins educativos, ou seja, pode haver implicações legais caso seja usado para fins lucrativos como em empresas:\nJetBrains: A JetBrains é uma famosa desenvolvedora de softwares para desenvolvimento de software e gerenciamente de projetos, sendo muito famosa pelas suas IDEs como IntelliJ, PyCharm e Webstorm. As três que citei anteriormente possuem uma versão Community que pode ser utilizada gratuitamente, porém a empresa oferece muitas outras IDEs para outras linguagens por um período de experimentação. Porém é possível obter uma licença para todas as IDEs fazendo uma solicitação em seu site, confira aqui.\nDBeaver: O DBeaver é uma ferramenta de acesso e manutenção de banco de dados bem plural. Em sua versão Community é possível acessar diversos bancos de dados diferentes, restrito a bancos de dados SQL. Em sua versão empresarial é possível acessar diversos outros tipos de banco de dados, destacando NoSQL, como Redis, MongoDB, BigTable e muitos outros. Felizmente é possível obter uma licença gratuita para a versão Enterprise bastando se cadastrar com o e-mail da faculdade aqui.\nGithub: O Github por si só já oferece uma infinidade de serviços excelentes de forma gratuita, então é possível facilmente hospedar o código e utilizar os serviços de integração contínua, mesmo no nível gratuito, sem muitas dificuldades. Porém caso queira fazer um upgrade em sua conta ele também oferece um pacote para estudantes que permite o acesso ao Github Pro e muitos outros recursos educaionais, o cadastro é feito aqui.\nSamsung: A Samsung (e a Apple também, porém não cheguei a testar) oferece desconto para estudantes em seus produtos. É preciso prestar bastante atenção pois nem sempre o desconto é vantajoso em relação a outras lojas, porém no geral é sim mais barato e valor apena pesquisar no site deles. Para ter acesso você deverá fazer o cadastro que se inicia ao tentar fazer login aqui.\nSó com as dicas acima já é possível economizar pelo menos mais de R$ 1000 por ano com licenças e também pelos descontos, assim não deixe de correr atrás destes descontos.\nCaso saiba de mais algum serviço que ofereça benefício para estudantes coloque aqui nos comentários, vou adorar saber e complementar a lista acima.\n","permalink":"https://blog.lucaspolo.dev/posts/coisas-gratis-para-estudantes/","summary":"\u003cp\u003eA vida de estudante não é fácil, no meu tempo ainda tínhamos o custo da xerox mas hoje felizmente isso é passado e as coisas são digitais. Mas logo tudo isso se converte em custos na compra de equipamentos, sendo necessário pelo menos um tablet para conseguir frequentar as aulas, custo na aquisição de software e muitas outras coisas. Felizmente algumas empresas oferecem descontos e até produtos inteiramente grátis para estudantes, e eu que voltei a ser estudante, estou aproveitando isso melhor agora.\u003c/p\u003e","title":"Coisas grátis para estudantes"},{"content":"Este ano as coisas parecem estar um pouco melhores do que nos anos anteriores, temos um pouco mais de perspectiva no que tange a nossa saúde, ficamos um pouco mais tranquilos e um pouco mais seguros, e isso é bom.\nDepois de muitas postagens no ano passado neste blog em torno de dezembro eu confesso que fiquei um tanto quanto sem assuntos, as coisas estavam corridas e a cabeça precisava de um refresco, isso aconteceu e agora temos um ano inteiro pela frente. Passei por uma mudança de emprego que trás muitas coisas novas para a minha caminhada e com certeza irão agregar muito para mim e para este pequeno blog, então vamos fazer as coisas se movimentarem por aqui.\nPara não dizer que este não foi um post técnico (e não foi, mas fica a recomendação), essa semana em aprendi um pouco mais sobre covariância, contravariância e invariância e isso foi sensacional. Esbarrei no assunto estudando Scala (é uma das linguagens que na minha opnião levam a tipagem como um assunto prioritário, como Rust). Vou deixar aqui os materiais que li para aprender mais sobre o assunto:\nEm Python (inglês): https://blog.magrathealabs.com/pythons-covariance-and-contravariance-b422c63f57ac\nC# (inglês): https://www.pluralsight.com/guides/covariance-and-contravariance-csharp\nScala (Em Português 🇧🇷): https://codeoutputstream.wordpress.com/2013/11/15/scala-invariancia-covariancia-e-contravariancia/\nPretendo retomar esse assunto quando eu tiver uma base formal mais forte e fazer um post aqui.\nUm ótimo ano de 2022!\n","permalink":"https://blog.lucaspolo.dev/posts/feliz-2022/","summary":"\u003cp\u003eEste ano as coisas parecem estar um pouco melhores do que nos anos anteriores, temos um pouco mais de perspectiva no que tange a nossa saúde, ficamos um pouco mais tranquilos e um pouco mais seguros, e isso é bom.\u003c/p\u003e\n\u003cp\u003eDepois de muitas postagens no ano passado neste blog em torno de dezembro eu confesso que fiquei um tanto quanto sem assuntos, as coisas estavam corridas e a cabeça precisava de um refresco, isso aconteceu e agora temos um ano inteiro pela frente. Passei por uma mudança de emprego que trás muitas coisas novas para a minha caminhada e com certeza irão agregar muito para mim e para este pequeno blog, então vamos fazer as coisas se movimentarem por aqui.\u003c/p\u003e","title":"Feliz 2022!"},{"content":"Em alguns momento é possível que precisamos criar ciclos numéricos, por exemplo, vamos supor que desejamos contar de 0 até 5 e após isso retornar ao zero. Uma solução simples seria algo como:\n#include \u0026lt;stdio.h\u0026gt; int main(int argc, char* argv[]) { int i = 0; for(;;) { printf(\u0026#34;%d\\n\u0026#34;, i++); if (i == 5) { i = 0; } } return 0; } Este tipo de código funciona muito bem e é simples de entender, porém podemos usar a nosso favor a matemática e utilizando o operador módulo, que traz o resto da divisão, conseguimos o mesmo efeito:\n#include \u0026lt;stdio.h\u0026gt; int main(int argc, char* argv[]) { int i = 0; for(;;) { printf(\u0026#34;%d\\n\u0026#34;, i++); i = i % 5; } return 0; } Uma vantagem do operador módulo sobre o if é que ele também funciona para quando seguimos para a direção contrária, como podemos ver abaixo:\n#include \u0026lt;stdio.h\u0026gt; int main(int argc, char* argv[]) { int i = 0; for(;;) { printf(\u0026#34;%d\\n\u0026#34;, i--); i = i % 5; } return 0; } Uma vantagem dessa abordagem é que ela pode ser mais rápida pois evita saltos de código ao utilizar um operador matemático.\n","permalink":"https://blog.lucaspolo.dev/posts/usando-o-operador-de-modulo-para-criar-ciclos/","summary":"\u003cp\u003eEm alguns momento é possível que precisamos criar ciclos numéricos, por exemplo, vamos supor que desejamos contar de 0 até 5 e após isso retornar ao zero. Uma solução simples seria algo como:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e#include\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003emain\u003c/span\u003e(\u003cspan style=\"color:#8be9fd\"\u003eint\u003c/span\u003e argc, \u003cspan style=\"color:#8be9fd\"\u003echar\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e argv[]) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd\"\u003eint\u003c/span\u003e i \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e(;;) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#50fa7b\"\u003eprintf\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;%d\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u003c/span\u003e, i\u003cspan style=\"color:#ff79c6\"\u003e++\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (i \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\ti \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eEste tipo de código funciona muito bem e é simples de entender, porém podemos usar a nosso favor a matemática e utilizando o operador módulo, que traz o resto da divisão, conseguimos o mesmo efeito:\u003c/p\u003e","title":"Usando o operador de módulo para criar ciclos"},{"content":"O jq é uma ferramenta de linha de comando que permite fazer queries e transformações em arquivos JSON. Ela é muito interessante e útil quando queremos buscar dados diversos em arquivos muito grandes. Para utilizar ela é muito simples, após instalada você já pode fazer a query. Vamos usar de exemplo este JSON.\nA primeira coisa que podemos fazer é utilizar ele apenas para formatar, para isso basta executarmos o comando cat exemplo.json | jq:\nO que temos aqui é uma lista de objetos, vamos então listar o nome de todas as pessoas dessa lista cat exemplo.json | jq .[].name:Como podemos ver é muito simples, usamos o . (ponto) para indicar que estamos operando na raiz, os colchetes são para operações em lista, podemos especificar o índice passando algo como [1], ou até inicio e fim com [2:4]. Outra operação que podemos fazer é saber o tamanho de array usando o length cat exemplo.json | jq \u0026ldquo;length\u0026rdquo;:Podemos inclusive criar condicionais utilizando o jq, por exemplo baseado na operação de tamanho que fizemos anteriormente cat exemplo.json | jq \u0026lsquo;if .[].name == \u0026ldquo;Tanya Villarreal\u0026rdquo; then \u0026ldquo;Achou\u0026rdquo; else \u0026ldquo;Não Achou\u0026rdquo; end\u0026rsquo;:\nPodemos interpolar strings cat exemplo.json | jq \u0026lsquo;\u0026ldquo;O nome é (.[].name)\u0026rdquo;\u0026rsquo;:\nAlém dessas possibilidades o jq permite fazer diversas outras operações, como operações matemáticas, pipelines, maps e muito mais. Um lugar para aprender a usa-lo e treinar pode ser o jq play, uma versão online que permite treinar e até usar o jq sem instalar.]\nHá também implementações do jq dentro de linguagens, mas pode ser algo não tem performático do que usar as próprias estruturas de dados inerentes a própria linguagem.\n","permalink":"https://blog.lucaspolo.dev/posts/fazendo-queries-em-json-com-jq/","summary":"\u003cp\u003eO \u003cstrong\u003ejq\u003c/strong\u003e é uma ferramenta de linha de comando que permite fazer queries e transformações em arquivos JSON. Ela é muito interessante e útil quando queremos buscar dados diversos em arquivos muito grandes. Para utilizar ela é muito simples, após instalada você já pode fazer a query. \u003ca href=\"https://gist.github.com/lucaspolo/920380636c082b8c5fce124684760844\"\u003eVamos usar de exemplo este JSON\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eA primeira coisa que podemos fazer é utilizar ele apenas para formatar, para isso basta executarmos o comando \u003cstrong\u003ecat exemplo.json | jq\u003c/strong\u003e:\u003c/p\u003e","title":"Fazendo queries em JSON com jq"},{"content":"Alguns anos atrás fiz um bot no Telegram e me surpreendi como é simples e rápido fazer utilizando Python. O Telegram fornece uma API para seus bots e há varias bibliotecas em diversas linguagens para interagir de maneira simples com esta API. A primeira coisa que precisamos fazer é acessar o @BotFather e solicitar a criação de um novo bot.\nApós seguirmos as instruções e configurarmos o nosso bot receberemos um token que será utilizado por nós mais a frente.\nPara interagirmos com a API de bots do Telegram usaremos a biblioteca python-telegram-bot. Após instalar a biblioteca podemos fazer um simples script que é equivalente ao \u0026ldquo;Hello World!\u0026rdquo; dos bots do Telegram:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import os from telegram.ext import Updater, CommandHandler def hello_world(update, context): update.message.reply_text( \u0026#34;Olá Mundo! Sou o novo bot.\u0026#34; ) def main(): token = os.getenv(\u0026#39;TELEGRAM_TOKEN\u0026#39;) updater = Updater(token=token) dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler(\u0026#39;start\u0026#39;, hello_world)); updater.start_polling() if __name__ == \u0026#39;__main__\u0026#39;: main() O script é simples, lemos o token de uma variável de ambiente (você também poderia colocar direto no código, mas não recomendo fazer isso) e criamos os objetos do Telegram para subir o nosso bot. Na linha 15 fazemos o registro da função que irá responder um comando ao bot, nossa função é bem simples e apenas faz o envio de uma mensagem de texto. Após a configuração do bot iniciamos o polling, ou seja, o script fica ouvindo se há mensagens novas para responder. Assim entramos em nosso bot, enviamos o start e já recebemos a mensagem:\nComo podemos ver acima, recebemos o retorno conforme esperado. Como o handler é uma simples função Python nós podemos agora fazer algo mais complexo. Vamos expandir criando um novo handler para buscar o nome da rua dado um determinado CEP, utilizando a biblioteca requests que já utilizamos antes em outros posts:\nimport os from telegram.ext import Updater, CommandHandler import requests def hello_world(update, context): update.message.reply_text( \u0026#34;Olá Mundo! Sou o novo bot.\u0026#34; ) def busca_cep(update, context): zipcode=context.args[0] update.message.reply_text(f\u0026#39;Buscando endereço do CEP {zipcode}\u0026#39;) try: response = requests.get( url=f\u0026#39;https://viacep.com.br/ws/{zipcode}/json\u0026#39; ) response.raise_for_status() message = [ f\u0026#39;{k}: {v}\\n\u0026#39; for k, v in response.json().items() ] update.message.reply_text(\u0026#39;\u0026#39;.join(message)) except Exception as exc: update.message.reply_text(f\u0026#39;Problemas ao buscar endereço do CEP {zipcode}\u0026#39;) def main(): token = os.getenv(\u0026#39;TELEGRAM_TOKEN\u0026#39;) updater = Updater(token=token) dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler(\u0026#39;start\u0026#39;, hello_world)); dispatcher.add_handler(CommandHandler(\u0026#39;cep\u0026#39;, busca_cep, pass_args=True)); updater.start_polling() if __name__ == \u0026#39;__main__\u0026#39;: main() Para usar a nova funcionalidade do bot basta enviar o comando /cep CEP e ele irá retornar o CEP buscado na API do ViaCEP.\nNo manual da biblioteca e também no BotFather é possível encontrar muitos outros recursos que podem ser definidos para o bot, vale apena a leitura caso esteja pensando em fazer algo mais avançado.\n","permalink":"https://blog.lucaspolo.dev/posts/criando-um-bot-no-telegram/","summary":"\u003cp\u003eAlguns anos atrás fiz um bot no Telegram e me surpreendi como é simples e rápido fazer utilizando Python. O Telegram fornece uma API para seus bots e há varias bibliotecas em diversas linguagens para interagir de maneira simples com esta API. A primeira coisa que precisamos fazer é acessar o \u003ca href=\"https://t.me/botfather\"\u003e@BotFather\u003c/a\u003e e solicitar a criação de um novo bot.\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Conversa com o BotFather no Telegram: o comando /newbot, a escolha do nome e do usuário do bot e a mensagem final com o token de acesso à API\" loading=\"lazy\" src=\"/images/posts/criando-um-bot-no-telegram/bot_father.png\"\u003e\u003c/p\u003e","title":"Criando um bot no Telegram"},{"content":"O Amazon Web Services SNS é um serviço que permite a notificação de diversas formas, desde conexões com as finas SQS do SMS até o envio de mensagens SMS. É muito comum o serviço ser utilizado por empresas para mandar notificações para seus clientes e é muito simples de ser utilizado.\nA primeira coisa necessária para fazer o envio de SMS é a criação de usuário com permissões de acesso ao SNS na Amazon. Com o usuário criado basta instalar a biblioteca boto3 e assim podemos criar o script necessário. Primeiro é necessário criar um cliente que acessa o serviço do SNS:\nclient = boto3.client( \u0026#34;sns\u0026#34;, aws_access_key_id=\u0026#39;AWS_ACCESS_KEY_ID\u0026#39;, aws_secret_access_key=\u0026#39;AWS_SECRET_ACCESS_KEY\u0026#39;, region_name=\u0026#34;us-east-1\u0026#34; ) Com isso é possível agora de maneira muito simples fazer o envio de SMS, basta utilizarmos o método publish passando o número de telefone (como o serviço é mundial é necessário especificar o código do país com o \u0026ldquo;+\u0026rdquo; na frente):\nclient.publish( PhoneNumber=\u0026#39;+5511999998888\u0026#39;, Message=\u0026#39;Agora a mensagem será enviada para o telefone\u0026#39; ) Assim já será possível enviar mensagens utilizando o serviço. O número exibido para quem recebe a mensagem costuma ser o de 5 dígitos iniciando em \u0026ldquo;2\u0026rdquo;, mas podendo variar.\n","permalink":"https://blog.lucaspolo.dev/posts/enviando-sms-via-amazon-web-services-sns-com-python/","summary":"\u003cp\u003eO Amazon Web Services SNS é um serviço que permite a notificação de diversas formas, desde conexões com as finas SQS do SMS até o envio de mensagens SMS. É muito comum o serviço ser utilizado por empresas para mandar notificações para seus clientes e é muito simples de ser utilizado.\u003c/p\u003e\n\u003cp\u003eA primeira coisa necessária para fazer o envio de SMS é a criação de usuário com permissões de acesso ao SNS na Amazon. Com o usuário criado basta instalar a biblioteca \u003cstrong\u003eboto3\u003c/strong\u003e e assim podemos criar o script necessário. Primeiro é necessário criar um cliente que acessa o serviço do SNS:\u003c/p\u003e","title":"Enviando SMS via Amazon Web Services SNS com Python"},{"content":"Alguns anos atrás lendo o Programador Pragmático eu esbarrei em um conceito muito interessante, geração de código. O caso de uso era simples: em alguns momentos você precisava produzir diversas estruturas de código, as vezes em mais de uma linguagem, que seguiam os mesmos padrões e para evitar o trabalho manual era interessante fazer um gerador de código.\nO caso do livro era a geração de algumas estruturas de dados em diversas linguagens e aproveitando o aprendizado eu decidi estender o conceito para a geração de classes (projeto aqui), para isso era lido um código simples dizendo o nome da classe, seus atributos e também os modificadores de acesso, como abaixo:\nB + Pessoa A - nome:String A - teste1:int A # teste:char[10] A # teste:teste[56] A + desprotegido:float A - teste:float[34543] E Como podemos ver temos a definição de cada linha pela primeira letra, depois o modificador do atributo seguido de seu nome e tipo. É algo muito simples, mas lembro que foi neste exemplo a primeira vez que eu ouvi falar de expressões regulares, afinal o gerador de código era feito em Perl e expressões regulares para Perl são algo intrínseco da linguagem. Um exemplo das classes geradas em Java, C++ e PHP a partir da especificação acima é o abaixo:\n// Java public class Pessoa { private\tString nome; private\tint teste1; protected char[] teste = new char[10]; protected teste[] teste = new teste[56]; public\tfloat desprotegido; private float[] teste = new float[34543]; } // C++ class Pessoa { private: String nome; int teste1; char teste[10]; teste teste[56]; float teste[34543]; public: float desprotegido; }; // PHP class Pessoa { private\t$nome; private\t$teste1; protected $teste = array(10); protected $teste = array(56); public\t$desprotegido; private $teste = array(34543); } O conceito é poderoso, apesar de simples, afinal isso mostrou que a partir de uma especificação eu poderia gerar código, ou se quisermos ir um pouco além, significava que a partir de uma linguagem em poderia gerar código em outras linguagens.\nCom este aprendizado fiz alguns outros geradores de código, principalmente geração de comandos a partir de alguma lista de dados. O que mais usei foi um script para geração de comandos de macro para o TeraTerm (programa de terminal) permitindo automatizar diversas tarefas.\nVoltando para o conceito inicial do Programador Pragmático, o principal motivo de utilizar um gerador de código era evitar a duplicidade de código, o que é confuso, pois no final do meu exemplo acima o código estava triplicado, o que é verdade, mas nem tanto. Como a geração destas classes estava atrelada a um único arquivo de especificação a regra estava centralizada e o código gerado era praticamente um asset do meu projeto.\nEste conceito de geração de código inclusive pode ser uma sementinha inicial para outras coisas mais profundas, como criação de linguagens de script, compiladores e afins. No livro Crafting Intepreters que já citei aqui no blog mais de uma vez, além da geração de código \u0026ldquo;óbvia\u0026rdquo; que a construção de um compilador faz, o autor se aproveita do conceito mais simples de script de geração de código para gerar a árvore de sintaxe abstrada, permitindo assim após ter o script de geração ampliar a sintaxe apenas mudando algumas especificações.\nProvavelmente você faz ou já fez uso de alguma ferramenta de geração de código e também poderia se aproveitar do conceito em algum momento para economizar tempo e diminuir a quantidade de erros gerados pelo fardo da repetição.\n","permalink":"https://blog.lucaspolo.dev/posts/gerando-codigo-que-gera-codigo/","summary":"\u003cp\u003eAlguns anos atrás lendo o Programador Pragmático eu esbarrei em um conceito muito interessante, geração de código. O caso de uso era simples: em alguns momentos você precisava produzir diversas estruturas de código, as vezes em mais de uma linguagem, que seguiam os mesmos padrões e para evitar o trabalho manual era interessante fazer um gerador de código.\u003c/p\u003e\n\u003cp\u003eO caso do livro era a geração de algumas estruturas de dados em diversas linguagens e aproveitando o aprendizado eu decidi estender o conceito para a geração de classes (\u003ca href=\"https://github.com/lucaspolo/CodeGeneratorX\"\u003eprojeto aqui\u003c/a\u003e), para isso era lido um código simples dizendo o nome da classe, seus atributos e também os modificadores de acesso, como abaixo:\u003c/p\u003e","title":"Gerando código que gera código"},{"content":"Como vimos neste artigo postado anteriormente aqui no blog, o Celery é uma ferramenta que permite executar tarefas de maneira assíncrona através de mensageria. Isso por si só já traz diversos benefícios, mas também é possível imaginarmos criando tarefas que seriam executadas dados certos intervalos de tempo (por exemplo o disparo de processos serem executados de madrugada) ou durante horários específicos. Este trabalho pode ser feito manualmente, basta criarmos um programa em Python que analisa todos os parâmetros temporais cadastrados e dispare as tarefas na hora adequada invocando a função através do método .delay().\nApesar de ser interessante desenvolver algo assim a ideia não é tão nova e o próprio pessoal que desenvolve o Celery se adiantou no assunto e criou o Celery Beat, uma aplicação que permite invocar tarefas do Celery conforme o tempo cadastrado.\nPrimeiro criamos e configuramos a nossa task, por fins de simplicidade iremos usar um Redis rodando localmente como broker (no post anterior usamos o SQS, porém como é mais complexo de configurar, o Redis já nos atende bem):\nimport os import time from celery import Celery app = Celery(\u0026#39;tasks\u0026#39;, broker=os.getenv(\u0026#39;BROKER_URL\u0026#39;, \u0026#39;redis://localhost/0\u0026#39;)) @app.task def envia_email(): lista_de_usuarios = [ \u0026#39;Monica\u0026#39;, \u0026#39;Cebolinha\u0026#39;, \u0026#39;Magali\u0026#39;, \u0026#39;Cascão\u0026#39;, \u0026#39;Louco\u0026#39;, \u0026#39;Tina\u0026#39;, \u0026#39;Rolo\u0026#39;, ] for usuario in lista_de_usuarios: print(f\u0026#39;Enviando email para {usuario}...\u0026#39;) time.sleep(1) print(f\u0026#39;Email enviando para {usuario}!\u0026#39;) Após isso podemos fazer a invocação manualmente para testarmos. A saída será a invocação das funções:\nAgora iremos para a parte mais importante deste artigo, como realizar o agendamento de tasks e a maneira mais simples é dentro do próprio arquivo de tasks definirmos a configuração. Para o nosso teste vamos chamar a task que criamos a cada 10 segundos (apenas para não termos que esperar muito tempo):\nimport os import time from celery import Celery app = Celery(\u0026#39;tasks\u0026#39;, broker=os.getenv(\u0026#39;BROKER_URL\u0026#39;, \u0026#39;redis://localhost/0\u0026#39;)) @app.task def envia_email(): ... app.conf.beat_schedule = { \u0026#39;envia-emails-a-cada-30-segundas\u0026#39;: { \u0026#39;task\u0026#39;: \u0026#39;tasks.envia_email\u0026#39;, \u0026#39;schedule\u0026#39;: 10.0, } } E executamos: celery -A tasks beat\nApós um pequeno intervalo de tempo vemos a execução da nossa task como se tivéssemos chamados manualmente.\nPara melhorar a nossa estrutura podemos separar a configuração do projeto, as tasks e o startup. Para isso basta separarmos alguns objetos em mais módulos e alterar algumas coisas simples:\n## config.py CELERY_BROKER_URL = \u0026#39;redis://localhost/0\u0026#39; CELERY_BEAT_SCHEDULE = { \u0026#39;envia-emails-a-cada-30-segundas\u0026#39;: { \u0026#39;task\u0026#39;: \u0026#39;tasks.envia_email\u0026#39;, \u0026#39;schedule\u0026#39;: 10.0, } } ## tasks.py import time from main import app @app.task def envia_email(): lista_de_usuarios = [ \u0026#39;Monica\u0026#39;, \u0026#39;Cebolinha\u0026#39;, \u0026#39;Magali\u0026#39;, \u0026#39;Cascão\u0026#39;, \u0026#39;Louco\u0026#39;, \u0026#39;Tina\u0026#39;, \u0026#39;Rolo\u0026#39;, ] for usuario in lista_de_usuarios: print(f\u0026#39;Enviando email para {usuario}...\u0026#39;) time.sleep(1) print(f\u0026#39;Email enviando para {usuario}!\u0026#39;) ## main.py from celery import Celery app = Celery(\u0026#39;tasks\u0026#39;) app.autodiscover_tasks(lambda: [\u0026#39;tasks\u0026#39;]) app.config_from_object(\u0026#39;config\u0026#39;, namespace=\u0026#39;CELERY\u0026#39;) Com isso temos uma estrutura de tarefas agendadas que pode ir para produção. A estrutura de componentes pode ser vista abaixo, expandindo o exemplo que fizemos no post anterior:\n","permalink":"https://blog.lucaspolo.dev/posts/criando-tarefas-perodicas-com-o-celery-beat/","summary":"\u003cp\u003eComo vimos neste artigo postado anteriormente aqui no blog, o Celery é uma ferramenta que permite executar tarefas de maneira assíncrona através de mensageria. Isso por si só já traz diversos benefícios, mas também é possível imaginarmos criando tarefas que seriam executadas dados certos intervalos de tempo (por exemplo o disparo de processos serem executados de madrugada) ou durante horários específicos. Este trabalho pode ser feito manualmente, basta criarmos um programa em Python que analisa todos os parâmetros temporais cadastrados e dispare as tarefas na hora adequada invocando a função através do método \u003cstrong\u003e.delay()\u003c/strong\u003e.\u003c/p\u003e","title":"Criando tarefas periódicas com o Celery Beat"},{"content":"\nO Redis é um dos projetos mais interessantes que já usei desenvolvendo software. Por ser um banco de dados em memória sua velocidade é bem alta e a versatilidade dele muito grande. Utilizo ele mais comumente para o armazenamento de cache, principalmente objetos serializados em sequências de bytes (ou seja, um JSON sem formatação), mas a utilidade dele vai muito além disso pois permite armazenar diversas outras estruturas mais complexas e uma das que me deparei utilizando recentemente foram os conjuntos.\nO meu caso de uso era bem simples, eu precisava armazenar diversos códigos únicos fornecidos por uma API em uma estrutura que seriam utilizados posteriormente, eles não poderiam ser usados duas vezes e eu não poderia criar uma estrutura em um banco relacional comum (e nem precisava), por isso decidimos usar conjuntos do Redis, que além de atender de maneira simples nosso problema também resolvia alguns problemas de concorrência que eu poderia ter com bancos relacionais, pois não estávamos afim de gerenciar um bloqueio de registro para garantir que ele não fosse usado por outra thread da aplicação e esse problema já vinha resolvido de brinde pelo fato do Redis ser single-threaded.\nConjuntos são objetos matemáticos que agrupam outros objetos com características em comum. Quando implementam estes objetos nas linguagens de programação e bancos de dados é comum termos acesso a algumas operações e características que tornam estas estruturas muito úteis. A primeira característica é que todos os elementos de um conjunto são únicos, ou seja, não se repetem, além disso é comum termos operações de inserção (add), remoção (pop), verificar se um elemento consta no conjunto e operações entre conjuntos como interseção e união.\nPrimeiro iremos inserir alguns elementos no nosso conjunto com a operação SADD:\n127.0.0.1:6379\u0026gt; SADD turma_da_monica Monica Cebolinha Cascão Magali (integer) 4 127.0.0.1:6379\u0026gt; Agora podemos fazer algumas operações, vamos verificar o tamanho do conjunto, ou melhor dizendo, sua cardinalidade com o SCARD:\n127.0.0.1:6379\u0026gt; SCARD turma_da_monica (integer) 4 127.0.0.1:6379\u0026gt; Vamos verificar se um elemento faz parte do conjunto com SISMEMBER:\n127.0.0.1:6379\u0026gt; SISMEMBER turma_da_monica Batman (integer) 0 127.0.0.1:6379\u0026gt; Quando o elemento está no conjunto é retornado 1, caso não é retornado 0. Podemos também remover um elemento qualquer do conjunto com o SPOP, mas é importante lembrar que o valor retornado não segue nenhum critério, pois conjuntos não possuem a obrigação de ter nenhuma ordem, ao contrário de listas:\n127.0.0.1:6379\u0026gt; SPOP turma_da_monica \u0026#34;Magali\u0026#34; 127.0.0.1:6379\u0026gt; Depois de removido podemos ver quais os membros que ainda compõem o conjunto com o SMEMBERS:\n127.0.0.1:6379\u0026gt; SMEMBERS turma_da_monica 1) \u0026#34;Cebolinha\u0026#34; 2) \u0026#34;Casc\\xc3\\xa3o\u0026#34; 3) \u0026#34;Monica\u0026#34; 127.0.0.1:6379\u0026gt; Além destas operações básicas os conjuntos do Redis também suportam operações como verificar interseção de conjuntos (elementos comuns em dois ou mais conjuntos), união (literalmente juntar conjuntos em um novo conjunto) e muito mais, vale apena conferir o manual das operações pois o mesmo é muito simples e fácil de entender. O mais importante é saber que o Redis suporta muito mais estruturas do que usamos habitualmente e é uma ferramenta incrível.\n","permalink":"https://blog.lucaspolo.dev/posts/utilizando-conjuntos-no-redis/","summary":"\u003cp\u003e\u003cimg alt=\"Logotipo do Redis\" loading=\"lazy\" src=\"/images/posts/utilizando-conjuntos-no-redis/redis.png\"\u003e\u003c/p\u003e\n\u003cp\u003eO Redis é um dos projetos mais interessantes que já usei desenvolvendo software. Por ser um banco de dados em memória sua velocidade é bem alta e a versatilidade dele muito grande. Utilizo ele mais comumente para o armazenamento de cache, principalmente objetos serializados em sequências de bytes (ou seja, um JSON sem formatação), mas a utilidade dele vai muito além disso pois permite armazenar diversas outras estruturas mais complexas e uma das que me deparei utilizando recentemente foram os conjuntos.\u003c/p\u003e","title":"Utilizando conjuntos no Redis"},{"content":"Alguns anos atrás comecei a estudar TDD e como desenvolvia principalmente em Java na época comecei a aprender um pouco mais sobre o JUnit, o principal framework de testes de unidade do Java e um dos primeiros de todas as linguagens. Para me ajudar eu criei um pequeno manual prático sobre ele:\nclass SimpleSnipetJUnitTest { private Calculator calculator; /** * Este método é invocado antes de cada teste, a annotation * facilita isso */ @Before public void setUp() { //Tudo aqui será executado antes, servindo por exemplo para inicializar. calculator = new Calculator(); } /** * Este método é invocado após os testes, servindo, como exemplo, para liberar recursos. */ @After public void finalize() { } /** * Teste comum, o método assertEquals realiza a operação de teste de igualdade. */ @Test public void testeSimples() { int result; result = calculator.sum(1, 2); assertEquals(3, result); } /** * Teste para números de ponto flutuante. * Destaque para o terceiro parâmetro, o delta, que define * qual a diferença decimal entre cada parâmetro. */ @Test public void testeDePontoFlutuante() { float result; result = calculator.divide(5, 2); //O terceiro parâmetro é a diferença máxima entre os floats assertEquals(2.5, result, 0.1) } /** * Teste para exceções * Se não disparar a exceção, o método falha. */ @Test (expected= CalculatorException.class) public void testeDeExcecao() { int result; result = calculator.divide(5, 0); } } ","permalink":"https://blog.lucaspolo.dev/posts/manual-basico-do-junit/","summary":"\u003cp\u003eAlguns anos atrás comecei a estudar TDD e como desenvolvia principalmente em Java na época comecei a aprender um pouco mais sobre o JUnit, o principal framework de testes de unidade do Java e um dos primeiros de todas as linguagens. Para me ajudar eu criei um pequeno manual prático sobre ele:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eSimpleSnipetJUnitTest\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprivate\u003c/span\u003e Calculator calculator;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  * Este método é invocado antes de cada teste, a annotation\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e          * facilita isso\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Before\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003esetUp\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e//Tudo aqui será executado antes, servindo por exemplo para inicializar.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tcalculator \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e Calculator();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e          * Este método é invocado após os testes, servindo, como exemplo, para liberar recursos.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e          */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        @After\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003efinalize\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e          * Teste comum, o método assertEquals realiza a operação de teste de igualdade.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e          */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Test\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003etesteSimples\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd\"\u003eint\u003c/span\u003e result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tresult \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e calculator.\u003cspan style=\"color:#50fa7b\"\u003esum\u003c/span\u003e(1, 2);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tassertEquals(3, result);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  * Teste para números de ponto flutuante.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  * Destaque para o terceiro parâmetro, o delta, que define\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e          * qual a diferença decimal entre cada parâmetro.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Test\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003etesteDePontoFlutuante\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd\"\u003efloat\u003c/span\u003e result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tresult \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e calculator.\u003cspan style=\"color:#50fa7b\"\u003edivide\u003c/span\u003e(5, 2);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#6272a4\"\u003e//O terceiro parâmetro é a diferença máxima entre os floats\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tassertEquals(2.\u003cspan style=\"color:#50fa7b\"\u003e5\u003c/span\u003e, result, 0.\u003cspan style=\"color:#50fa7b\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#6272a4\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  * Teste para exceções\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  * Se não disparar a exceção, o método falha.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e\t  */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@Test (expected\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e CalculatorException.\u003cspan style=\"color:#50fa7b\"\u003eclass\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003etesteDeExcecao\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#8be9fd\"\u003eint\u003c/span\u003e result;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\tresult \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e calculator.\u003cspan style=\"color:#50fa7b\"\u003edivide\u003c/span\u003e(5, 0);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Manual básico do JUnit"},{"content":"Algum tempo atrás precisei aprender a fazer upload de arquivos para o Google Cloud Storage. Uma das coisas que eu gosto de fazer para me ajudar aprender a fazer algo é criar um scriptzinho com o conceito do que quero, sem aplicar em grandes projetos, evitando assim grandes complexidades.\nAssim na época eu criei este script simples que faz o upload do arquivo em um bucket do GCS. A primeira coisa que você precisa fazer é ter instalada a biblioteca, para isso temos o bom e velho pip:\npip install --upgrade google-cloud-storage Depois disso você precisa definir uma variável de ambiente apontando para o arquivo de credenciais do Google Cloud Platform:\nexport GOOGLE_APPLICATION_CREDENTIALS=\u0026#34;/home/user/Downloads/service-account-file.json\u0026#34; Com a biblioteca instalada e a variável definida podemos executar o script abaixo e fazer upload de arquivos:\nfrom datetime import timezone, datetime from typing import BinaryIO from google.cloud import storage def upload_file( data: BinaryIO, bucket: str, file_path: str, link_lifetime: int = 3600 ) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34; Função que realiza o upload do arquivo \u0026#34;\u0026#34;\u0026#34; storage_client = storage.Client() bucket = storage_client.bucket(bucket) blob = bucket.blob(file_path) blob.upload_from_file(data) # Faz o upload do arquivo binário e cria um objeto associado ao arquivo lifetime = int( datetime.now(tz=timezone.utc).timestamp() ) + link_lifetime # Gera um link para o arquivo com tempo de expiração url = blob.generate_signed_url(lifetime) return def main(): bucket = \u0026#39;meu-pequeno-bucket\u0026#39; # Bucket name in GCS file_name = \u0026#39;arquivo_legal.pdf\u0026#39; # Filename with open(file_name, \u0026#39;rb\u0026#39;) as f: url = upload_file( data=f, bucket=bucket, file_path=file_name, ) print(f\u0026#39;URL for file: {url}\u0026#39;) if __name__ == \u0026#34;__main__\u0026#34;: main() Esta biblioteca é síncrona e existem alternativas assíncronas bem interessantes e com uma API parecida, mas não igual, vale apena considerar o uso.\n","permalink":"https://blog.lucaspolo.dev/posts/fazendo-upload-de-arquivos-para-o-google-cloud-storage-com-python-2/","summary":"\u003cp\u003eAlgum tempo atrás precisei aprender a fazer upload de arquivos para o Google Cloud Storage. Uma das coisas que eu gosto de fazer para me ajudar aprender a fazer algo é criar um scriptzinho com o conceito do que quero, sem aplicar em grandes projetos, evitando assim grandes complexidades.\u003c/p\u003e\n\u003cp\u003eAssim na época eu criei este script simples que faz o upload do arquivo em um bucket do GCS. A primeira coisa que você precisa fazer é ter instalada a biblioteca, para isso temos o bom e velho pip:\u003c/p\u003e","title":"Fazendo upload de arquivos para o Google Cloud Storage com Python"},{"content":"Vira e mexe precisamos testar o tempo de algo que roda em linha de comando, seja uma requisição através de cURL ou algum scripts/aplicação que construímos.\nO jeito mais simples e onipresente nas interfaces de linha de comando do Linux é o time. Ele executa o comando passado para ele através de parâmetro e diz qual foi o tempo de execução:\nResultado da execução do time\nO time pode ajudar muito, principalmente quando queremos comparar escalas de tempo muito diferentes, por exemplo uma mudança de código que mudou o tempo de execução de 1s para 100ms. Porém como a medida pode variar muito de execução devido a diversos fatores (cache, resolução de DNS, etc) testar apenas uma única vez pode não trazer resultados muito acurados, pois não temos tempo médio nem a variância do tempo. Para isso encontrei uma outra aplicação chamada hyperfine.\nO hyperfine executa diversas vezes o comando e traz algumas estatísticas completas da execução, testando com o mesmo script que usamos acima temos:\nlucaspolo@notebook:~$ hyperfine python fibonacci.py Benchmark #1: python Time (mean ± σ): 44.9 ms ± 4.5 ms [User: 50.8 ms, System: 8.2 ms] Range (min … max): 42.1 ms … 71.3 ms 41 runs Warning: The first benchmarking run for this command was significantly slower than the rest (71.3 ms). This could be caused by (filesystem) caches that were not filled until after the first run. You should consider using the \u0026#39;--warmup\u0026#39; option to fill those caches before the actual benchmark. Alternatively, use the \u0026#39;--prepare\u0026#39; option to clear the caches before each timing run. Benchmark #2: fibonacci.py Error: Command terminated with non-zero exit code. Use the \u0026#39;-i\u0026#39;/\u0026#39;--ignore-failure\u0026#39; option if you want to ignore this. Alternatively, use the \u0026#39;--show-output\u0026#39; option to debug what went wrong. lucaspolo@notebook:~$ No resultado acima já podemos ver com mais precisão o que aconteceu. Vimos que o script rodou com o tempo de 44.9ms com o desvio padrão de 4.5ms, além do teste de menor tempo e maior tempo. Outro ponto que foi alertado para nós é que a primeira execução levou o tempo 71.3ms, possivelmente por algum cache na hora de carregar o arquivo em disco na primeira vez, o que também poderia acontecer ao fazer requisições e afins (como falei, podemos ter caches de DNS sendo esquentados e muitos outros fatores de I/O). Para ajudar nisso podemos rodar o hyperfine com um parâmetro que faz executar algumas vezes o processo antes de efetivamente iniciar a contagem, \u0026ldquo;esquentando\u0026rdquo; assim o nosso ambiente:\nlucaspolo@notebook:~$ hyperfine --warmup 3 python fibonacci.py Benchmark #1: python Time (mean ± σ): 44.2 ms ± 1.8 ms [User: 49.1 ms, System: 8.8 ms] Range (min … max): 41.2 ms … 51.0 ms 67 runs Benchmark #2: fibonacci.py Error: Command terminated with non-zero exit code. Use the \u0026#39;-i\u0026#39;/\u0026#39;--ignore-failure\u0026#39; option if you want to ignore this. Alternatively, use the \u0026#39;--show-output\u0026#39; option to debug what went wrong. Como agora esquentamos melhor o ambiente a variância diminui bastante e temos uma visão mais realista do tempo de execução.\nEstes são apenas alguns pontos básicos de como o hyperfine pode ajudar em benchmarks de ferramentas de linha de comando, no seu repositório é possível encontrar muitas outras funcionalidades, como parametrização de entrada do comando, execução de comandos de preparação para cada teste (as vezes queremos justamente testar o tempo sem caches, ai podemos limpar antes) e muito mais.\nO mais importante neste ponto não é a ferramenta utilizada em si, mas a busca por métricas que possam embasar melhor nossas decisões.\n","permalink":"https://blog.lucaspolo.dev/posts/medindo-o-tempo-de-aplicacoes-de-linha-de-comando/","summary":"\u003cp\u003eVira e mexe precisamos testar o tempo de algo que roda em linha de comando, seja uma requisição através de cURL ou algum scripts/aplicação que construímos.\u003c/p\u003e\n\u003cp\u003eO jeito mais simples e onipresente nas interfaces de linha de comando do Linux é o \u003cstrong\u003etime\u003c/strong\u003e. Ele executa o comando passado para ele através de parâmetro e diz qual foi o tempo de execução:\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"time python fibonacci.py\" loading=\"lazy\" src=\"/images/posts/medindo-o-tempo-de-aplicacoes-de-linha-de-comando/Screenshot_from_2021-10-07_00-15-02.png\"\u003e\n\u003cem\u003eResultado da execução do time\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eO \u003cstrong\u003etime\u003c/strong\u003e pode ajudar muito, principalmente quando queremos comparar escalas de tempo muito diferentes, por exemplo uma mudança de código que mudou o tempo de execução de 1s para 100ms. Porém como a medida pode variar muito de execução devido a diversos fatores (cache, resolução de DNS, etc) testar apenas uma única vez pode não trazer resultados muito acurados, pois não temos tempo médio nem a variância do tempo. Para isso encontrei uma outra aplicação chamada \u003ca href=\"https://github.com/sharkdp/hyperfine\"\u003e\u003cstrong\u003ehyperfine\u003c/strong\u003e\u003c/a\u003e.\u003c/p\u003e","title":"Medindo o tempo de aplicações de linha de comando"},{"content":"Há alguma tempo atrás eu aprendi um pouco de Scala, uma linguagem muito interessante que roda sobre a JVM. Apesar de ser muito similar ao Java a primeira vista logo depois de um pouco mais de aprendizado lidamos com recursos muito diferentes do que temos na linguagem mais velha. Um recurso que me surpreendeu foi o casamento de padrões, ou pattern matching em inglês e vou usa-la de exemplo aqui pois até onde conheço o pattern matching do Scala é um dos mais completos. Diversas outras linguagens implementam também o recurso de maneira similar e as vezes com um pouco menos de poder, por isso vale conferir a documentação antes de prosseguir.\nO casamento de padrões permite verificar se um dado objeto segue determinado padrão especificado pelo programador e muitas vezes ele é utilizado para desempacotar valores de um objeto e/ou verificar condições. Um exemplo pode ser visto a seguir em Scala:\n1 2 3 4 5 6 7 8 9 10 object CasamentoDePadroes extends App { var x: Any = \u0026#34;Desconhecido porém string\u0026#34;; x match { case \u0026#34;oi\u0026#34; =\u0026gt; println(\u0026#34;Hello\u0026#34;) case \u0026#34;Scala\u0026#34; =\u0026gt; println(\u0026#34;Hello Scala\u0026#34;) case value: String =\u0026gt; println(s\u0026#34;This is a string: $value\u0026#34;) case _ =\u0026gt; println(\u0026#34;A strange object\u0026#34;) } } Este é um dos exemplos mais comuns, parecido com o famigerado switch/case vemos que podemos testar valores e tipos com o casamento de padrões. Nas linhas 5 e 6 testamos o padrão contra valores, na linha 7 testamos contra um tipo (no caso String) e na linha 8 usamos uma expressão para capturar qualquer que seja o retorno.\nO pattern matching do Scala também pode ser usado para desembrulhar valores de objetos:\n1 2 3 4 5 6 7 8 9 10 11 12 13 object CasamentoDePadroes extends App { case class Pessoa(nome: String, idade: Int); var pessoa = Pessoa(\u0026#34;Linus\u0026#34;, 51); pessoa match { case Pessoa(\u0026#34;Lucas\u0026#34;, _) =\u0026gt; println(\u0026#34;Olá programador Lucas\u0026#34;) case Pessoa(nome, idade) if idade \u0026gt; 50 =\u0026gt; println(s\u0026#34;Olá Sr(a) $nome\u0026#34;) case Pessoa(nome, _) =\u0026gt; println(s\u0026#34;Olá $nome\u0026#34;) case _: Pessoa =\u0026gt; println(\u0026#34;Olá desconhecido\u0026#34;) case _ =\u0026gt; println(\u0026#34;Error\u0026#34;) } } Neste exemplo brincamos muito mais com o casamento de padrões, além da estrutura similar ao switch/case também olhamos os valores internos do objeto em avaliação. Na linha 7 verificamos o nome da pessoa e caso seja \u0026ldquo;Lucas\u0026rdquo; exibimos uma mensagem personalizada, na linha 8 utilizamos uma funcionalidade chamada guarda, que é basicamente uma condição adicional ao pattern matching, assim se a pessoa tiver mais de 50 anos tratamos ela por um pronome personalizado. Verificamos casos menos específicos na linha 9 e 10 e caso chegue na linha 11 sabemos que temos um erro pois o objeto não é uma pessoa.\nO pattern matching do Scala também atua como expressão, podendo retornar valores específicos se necessário (na verdade em Scala tudo é expressão):\nobject CasamentoDePadroes extends App { case class Pessoa(nome: String, idade: Int); var pessoa = Pessoa(\u0026#34;Linus\u0026#34;, 51); var mensagem = pessoa match { case Pessoa(\u0026#34;Lucas\u0026#34;, _) =\u0026gt; \u0026#34;Olá programador Lucas\u0026#34; case Pessoa(nome, idade) if idade \u0026gt; 50 =\u0026gt; s\u0026#34;Olá Sr(a) $nome\u0026#34; case Pessoa(nome, _) =\u0026gt; s\u0026#34;Olá $nome\u0026#34; case _: Pessoa =\u0026gt; \u0026#34;Olá desconhecido\u0026#34; case _ =\u0026gt; \u0026#34;Error\u0026#34; } println(mensagem) } Na verdade o pattern matching do Scala é usado em toda a linguagem é uma das bases para a programação funcional dela. O desembrulho de alguns parâmetros é permitido através justamente por causa do pattern matching:\nobject CasamentoDePadroes extends App { // Pattern matching apicado a recuperação de valores de uma lista val lista = List(1,2,3,4,5) val primeiro :: resto = lista println(primeiro) println(resto) // Utilizando guardas como filtro val pares = for { x \u0026lt;- lista if x % 2 == 0 } yield x print(pares) } Além destes exemplos o Scala permite muito mais coisas com seu casamento de padrões e outras linguagens como Rust, C#, Python (3.10), Java (17), etc oferecem esse recurso em algum nível. Vale apena consultar se sua linguagem possui este recurso, pois permite reduzir deixar o código muito mais organizado, principalmente aliado a orientação a objetos e tipagem.\n","permalink":"https://blog.lucaspolo.dev/posts/casamento-de-padroes-pattern-matching/","summary":"\u003cp\u003eHá alguma tempo atrás eu aprendi um pouco de Scala, uma linguagem muito interessante que roda sobre a JVM. Apesar de ser muito similar ao Java a primeira vista logo depois de um pouco mais de aprendizado lidamos com recursos muito diferentes do que temos na linguagem mais velha. Um recurso que me surpreendeu foi o casamento de padrões, ou pattern matching em inglês e vou usa-la de exemplo aqui pois até onde conheço o pattern matching do Scala é um dos mais completos. Diversas outras linguagens implementam também o recurso de maneira similar e as vezes com um pouco menos de poder, por isso vale conferir a documentação antes de prosseguir.\u003c/p\u003e","title":"Casamento de padrões (Pattern Matching)"},{"content":"Recentemente voltei a mexer mais com Java devido ao trabalho e também alguns conteúdos que eu estava acompanhando que utilizam a linguagem. Como estou utilizando o IntelliJ como IDE ela sugeriu algo muito interessante e que passei adotar sempre que posso, o nova sintaxe do switch/case.\nA instrução switch case comum do Java segue algo muito similar a já implementada no C, um exemplo simples:\npackage com.company; public class Main { public static void main(String[] args) { var nome = \u0026#34;Cebolinha\u0026#34;; switch(nome) { case \u0026#34;Lucas\u0026#34;: System.out.println(\u0026#34;Bem vindo programador Lucas\u0026#34;); break; case \u0026#34;Grace\u0026#34;: System.out.println(\u0026#34;Bem vinda programadora Grace Hopper\u0026#34;); break; default: System.out.println(\u0026#34;Bem vindx pessoa programadora \u0026#34; + nome); } } } Esta é a estrutura comum que já conhecemos, como você pode ver temos os casos específicos que tratamos, o caso padrão e para que a avaliação do switch/case pare precisamos utilizar a clausula break, o que chega a me dar \u0026ldquo;gastura\u0026rdquo; em switch/cases muito grandes.\nAlgumas outras linguagens (Rust, Scala e outras) tem uma síntaxe construida sobre casamento de padrões e implementam uma estrutura similar porém um pouco mais expressiva e eficiente. No Java 13 algo similar (mas ainda não tão poderoso) foi incluído e agora podemos ter uma nova síntaxe que utiliza o operador -\u0026gt; (seta) e já mostra a diferença:\npackage com.company; public class Main { public static void main(String[] args) { var nome = \u0026#34;Cebolinha\u0026#34;; switch (nome) { case \u0026#34;Lucas\u0026#34; -\u0026gt; System.out.println(\u0026#34;Bem vindo programador Lucas\u0026#34;); case \u0026#34;Grace\u0026#34; -\u0026gt; System.out.println(\u0026#34;Bem vinda programadora Grace Hopper\u0026#34;); default -\u0026gt; System.out.println(\u0026#34;Bem vindx pessoa programadora \u0026#34; + nome); } } } Agora já não é mais necessário utilizar o break para encerrar a busca, pois quando houver um caso que seja positivo ele executa e encerra a avaliação. Para casos de avaliação de Enums fica muito interessante, como podemos ver no exemplo abaixo:\npackage com.company; public class Main { public enum Veiculos { BICICLETA, MOTO, CARRO, ONIBUS, CAMINHAO } public static void main(String[] args) { var veiculo = Veiculos.CAMINHAO; float valorPedagio = 0; switch (veiculo) { case MOTO -\u0026gt; valorPedagio = 1; case CARRO -\u0026gt; valorPedagio = 2; case CAMINHAO -\u0026gt; valorPedagio = 3; case ONIBUS -\u0026gt; valorPedagio = 4; } System.out.println(\u0026#34;Você deverá pagar um pedágio de \u0026#34; + valorPedagio); } } O ponto que talvez seja mais interessante é que o switch/case passa a ser também uma expressão, ou seja, pode retornar valores, para isso basta utilizarmos numa atribuição, reduzindo bastante o caso anterior:\npackage com.company; public class Main { public enum Veiculos { BICICLETA, MOTO, CARRO, ONIBUS, CAMINHAO } public static void main(String[] args) { var veiculo = Veiculos.CAMINHAO; float valorPedagio = switch (veiculo) { case MOTO -\u0026gt; valorPedagio = 1; case CARRO -\u0026gt; valorPedagio = 2; case CAMINHAO -\u0026gt; valorPedagio = 3; case ONIBUS -\u0026gt; valorPedagio = 4; default -\u0026gt; 0; // Como não cobrimos todos os casos eu preciso definir um default }; // Por ser uma expressão precisa terminar com ; System.out.println(\u0026#34;Você deverá pagar um pedágio de \u0026#34; + valorPedagio); } } Para garantir que a variável fique corretamente preenchida (já pensou caso não batesse com nenhum valor? Seria algo indefinido) é obrigatório avaliar todos os casos, no caso de umde Enums é necessário cobrir todos os casos nem que seja definindo um default. Outros tipos basta incluir um caso default, como String e tipos numéricos.\nNos exemplos anteriores só utilizamos expressões de uma linha nos cases, mas é possível utilizar blocos também para computar algo:\npackage com.company; public class Main { public enum Veiculos { BICICLETA(0), MOTO(1), CARRO(2), ONIBUS(4), CAMINHAO(3); private final float tarifa; Veiculos(float tarifa) { this.tarifa = tarifa; } } public static void main(String[] args) { var veiculo = Veiculos.CAMINHAO; float valorPedagio = switch (veiculo) { case MOTO, CARRO -\u0026gt; veiculo.tarifa; case ONIBUS, CAMINHAO -\u0026gt; { var adicional = 5; yield veiculo.tarifa + adicional; } default -\u0026gt; 0; }; System.out.println(\u0026#34;Você deverá pagar um pedágio de \u0026#34; + valorPedagio); } } Para retornar um valor para o switch nos casos de blocos utilizamos a palavra yield (que fica similar ao return de uma função).\nVer essa nova sintaxe aliada as novidades que foram incluídas desde o Java 8 irão permitir um código muito mais expressivo e coeso. Além disso no recém lançado Java 17 está sendo incluída uma proposta de casamento de padrões (pattern matching) que irá aumentar ainda mais o poder do switch/case, pois além de avaliar valores também será capaz de avaliar tipos, iremos comentar mais sobre isso em um post futuro.\n","permalink":"https://blog.lucaspolo.dev/posts/o-novo-mas-nem-tanto-switch-case-do-java/","summary":"\u003cp\u003eRecentemente voltei a mexer mais com Java devido ao trabalho e também alguns conteúdos que eu estava acompanhando que utilizam a linguagem. Como estou utilizando o IntelliJ como IDE ela sugeriu algo muito interessante e que passei adotar sempre que posso, o nova sintaxe do switch/case.\u003c/p\u003e\n\u003cp\u003eA instrução switch case comum do Java segue algo muito similar a já implementada no C, um exemplo simples:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003epackage\u003c/span\u003e com.company;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eMain\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003emain\u003c/span\u003e(String\u003cspan style=\"color:#ff79c6\"\u003e[]\u003c/span\u003e args) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003evar\u003c/span\u003e nome \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Cebolinha\u0026#34;\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eswitch\u003c/span\u003e(nome) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Lucas\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Bem vindo programador Lucas\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ecase\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Grace\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Bem vinda programadora Grace Hopper\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003edefault\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Bem vindx pessoa programadora \u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e nome);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eEsta é a estrutura comum que já conhecemos, como você pode ver temos os casos específicos que tratamos, o caso padrão e para que a avaliação do switch/case pare precisamos utilizar a clausula \u003cem\u003ebreak\u003c/em\u003e, o que chega a me dar \u0026ldquo;gastura\u0026rdquo; em switch/cases muito grandes.\u003c/p\u003e","title":"O novo (mas nem tanto) switch/case do Java"},{"content":"Depois que comecei a programar em Python no dia a dia eu me deparei com uma das ferramentas mais legais de teste que conheci, o Pytest. Por padrão o Python já vem com uma ferramenta de testes chamada Unittest, que é muito boa e funcional, porém como ela foi criada junto com o Python algumas arestas dela ficaram soltas, principalmente por não utilizar toda a potência que a própria linguagem oferece. Aqui eu vou deixar algumas coisas muito interessantes que uso no meu dia a dia e como podem servir principalmente como um guia rápido do Pytest.\nO Pytest é compatível com o unittest Caso você tenha algum receio em migrar do Unittest para o Pytest a primeira novidade é que ele é compatível com os testes escritos em Unittest, assim você não perde em nada ao tentar executar o teste abaixo:\nPytest executando cenários de teste do unittest Com isso a migração para o Pytest é mais simples caso seu projeto já utilize o unittest como framework de teste.\nFixtures: objetos reutilizáveis e setUp() e tearDown() O Pytest consta com um mecanismo de criação de dependências de testes chamado fixtures. Basicamente uma fixture é um \u0026ldquo;acessório\u0026rdquo; que você utilizará em um ou mais testes que será injetado no seu teste a partir de uma assinatura de função. Um exemplo simples de como funciona é o seguinte:\nimport pytest @pytest.fixture def cliente(): return { \u0026#39;nome\u0026#39;: \u0026#39;Cebolinha\u0026#39;, \u0026#39;idade\u0026#39;: 5 } def test_cliente_possui_nome_cebolinha(cliente): assert cliente.get(\u0026#39;nome\u0026#39;) == \u0026#39;Cebolinha\u0026#39; Perceba que apenas com a assinatura da função tendo o mesmo nome da fixture criada ela já será automaticamente repassada para a função de teste. Mas isso é só o começo das fixtures, perceba que no unittest utilizamos muito os métodos setUp() e tearDown() para definir tudo que precisa rodar antes e depois dos nossos testes (por exemplo criar e limpar registros em um banco de dados ou cache), mas como os testes do Pytest não precisam estar contidos em classes como podemos ter um comportamento similar? Novamente as fixtures podem nos ajudar com isto!\nQuando a fixture é um generator (funções em Python com o yield no corpo) o Pytest lida com ela de uma forma diferentes, vejamos o exemplo abaixo:\nimport pytest @pytest.fixture def configuracao(): print(\u0026#39;Configurando coisas necessárias...\\n\u0026#39;); yield \u0026#39;valor da fixture\u0026#39; print(\u0026#39;Fazendo limpeza...\\n\u0026#39;) def test_com_fixture_generator(configuracao): print(\u0026#34;Testando\\n\u0026#34;) assert configuracao == \u0026#39;valor da fixture\u0026#39; Executando o teste passando a flag -s ao final para imprimir os prints() podemos ver como foi executado:\n(.venv) lucaspolo@notebook:~/Tests/pytest_manual$ pytest test_fixture_generator.py -s ================================================= test session starts ================================================== platform linux -- Python 3.10.0rc1, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: /home/lucaspolo/Tests/pytest_manual collected 1 item test_fixture_generator.py Configurando coisas necessárias... Testando .Fazendo limpeza... ================================================== 1 passed in 0.00s =================================================== (.venv) lucaspolo@notebook:~/Tests/pytest_manual$ Veja que primeiro foi executado o código antes do yield, depois o código da função de testes e por último o código que veio depois do yield. Quem fez todo esse gerenciamento foi o próprio Pytest, que identificou que a função é um generator possibilitando controlarmos que códigos executam antes ou depois do cenário de teste em questão.\nPara elevar o nível da reutilização das fixtures é possível armazena-las em arquivos especiais que são lidos automaticamente,para isso basta armazenar a fixture em um arquivo conftest.py. O Pytest irá ler esse arquivo e disponibilizar as fixtures em todos os testes na mesma hierarquia ou nos pacotes abaixo:\nEsta é um pequeno começo sobre o poder do Pytest, ainda há muito o que falar sobre ele, principalmente alguns plugins que permitem executar casos de teste ainda mais complexos.\n","permalink":"https://blog.lucaspolo.dev/posts/pytest-pequeno-manual-para-o-dia-a-dia-fixtures/","summary":"\u003cp\u003eDepois que comecei a programar em Python no dia a dia eu me deparei com uma das ferramentas mais legais de teste que conheci, o Pytest. Por padrão o Python já vem com uma ferramenta de testes chamada Unittest, que é muito boa e funcional, porém como ela foi criada junto com o Python algumas arestas dela ficaram soltas, principalmente por não utilizar toda a potência que a própria linguagem oferece. Aqui eu vou deixar algumas coisas muito interessantes que uso no meu dia a dia e como podem servir principalmente como um guia rápido do Pytest.\u003c/p\u003e","title":"Pytest: Pequeno manual para o dia a dia - Fixtures"},{"content":"Acredito que todo programador já se perguntou ou irá se perguntar como as linguagens de programação são feitas, principalmente se você não teve nenhuma disciplina como compiladores na faculdade. Eu me fiz essa pergunta algumas vezes e aprendi muito com ela. Se você pesquisar na internet sobre como compiladores são feitos ou perguntar por ai um dos conteúdos que irá descobrir é o excelente, porém bem complexo para iniciantes, Compiladores: Princípios, técnicas e ferramentas de Alfred V. Aho Et al.\nO famigerado Livro do Dragão\nComo a capa indica, você irá enfrentar um dragão e por isso já precisa ser um guerreiro ou guerreira medieval. O livro é denso e confesso que não consegui acompanhar logo de cara, mas é reconhecidamente uma referência no mundo das linguagens de programação. Tentar iniciar por ele pode frustrar a pessoa e afasta-la do conteúdo por um tempo, algo que aconteceu comigo principalmente pela falta de prática que o livro tem em seu inicio.\nA minha sorte é que algum tempo atrás o Luciano Ramalho, escritor do Python Fluente, fez uma oficina de linguagens de programação no Garoa Hacker Clube e o gravou e disponibilizou as suas palestras online.\nEsse conteúdo é baseado no excelente artigo How to write a (Lisp) interpreter in Python do Peter Norvig, onde ele cria uma linguagem baseada em Lisp em Python, mostrando todo os processos para você conseguir interpretar uma linguagem de programação. O artigo é bem didático e se você conseguir acompanhar o texto em inglês vale apena lê-lo.\nCom o conteúdo do Luciano Ramalho e o artigo do Peter Norvig eu consegui ter uma visão muito interessante sobre como as linguagens de programação são feitas, principalmente as interpretadas e os conceitos iniciais de linguagens compiladas (que vão além das intepretadas pois transformam as estruturas de dados criadas no início para outras linguagens).\nAgora estou lendo o livro Crafting Interpreters de Robert Nystron. O Robert Nystron trabalha no Google no desenvolvimento da linguagem Dart, utilizada por exemplo no famoso framework para aplicações móveis Flutter. O livro que está disponível gratuitamente na internet e explica como criar interpretadores e compiladores, porém diferentemente do livro do dragão o Crafting Interpreters passa pelos conceitos teóricos como uma referência para a implementação prática que ele está fazendo. O livro é muito rico e segue um formato incremental de aprendizado, abusando de ilustrações e código explicado é um conteúdo que recomendo muito mesmo para quem domina apenas o básico de programação e orientação a objetos (mas não acho que seja um livro para iniciantes em programação).\nCrafting Interpreters de Robert Nystron\nO livro é basicamente dividido em duas partes, a primeira, a qual estou lendo agora, é dedicada a criação de um interpretador feito em Java para uma linguagem básica porém com diversos conceitos (funções de primeira ordem, classes, análise semântica do código) chamada Lox. Apesar do Java não ser a linguagem mais convidativa para iniciantes o autor não utiliza nenhum recurso mirabolante (apenas umas interfaces com um pouco de tipos genéricos, mas que é possível abstrair num primeiro momento), o que faz com o que o foco fique nos algoritmos utilizados e no entendimento dos conceitos e funcionalidades da Lox. Vamos desde a implementação de operadores simples criando assim uma calculadora básica até a criação de funções de primeira ordem e classes. Quase todos os capítulos encerram com um pequeno texto do autor discutindo os conceitos ensinados e também as diferenças entre diversas linguagens de programação e os prós e contras de cada decisão implementada em linguagens já bem conhecidas.\nA segunda parte do livro é dedicada a implementação em C da linguagem junto com uma máquina virtual, visando tópicos mais avançados como a própria máquina virtual, compilação e otimizações internas, avançando assim para os tópicos mais avançados.\nDepois irei tentar novamente enfrentar o dragão, acreditando que estarei mais preparado, o que é inclusive uma proposta do Robert Nystron no Crafting Interpreters. Mesmo que você nunca venha trabalhar implementando uma linguagem de programação a visão de como as linguagens são implementadas e também apreciar melhor cada decisão tomada nas linguagens que você utiliza.\n","permalink":"https://blog.lucaspolo.dev/posts/quem-programa-as-linguagens-de-programacao/","summary":"\u003cp\u003eAcredito que todo programador já se perguntou ou irá se perguntar como as linguagens de programação são feitas, principalmente se você não teve nenhuma disciplina como compiladores na faculdade. Eu me fiz essa pergunta algumas vezes e aprendi muito com ela. Se você pesquisar na internet sobre como compiladores são feitos ou perguntar por ai um dos conteúdos que irá descobrir é o excelente, porém bem complexo para iniciantes, Compiladores: Princípios, técnicas e ferramentas de Alfred V. Aho Et al.\u003c/p\u003e","title":"Quem programa as linguagens de programação?"},{"content":"Eu me lembro que em 2008 eu imaginei como seria criar um sistema operacional e na época eu busquei algo na internet para fazer uma introdução no assunto. Eu lembro que a primeira coisa que imaginei foi que pelo menos a \u0026ldquo;entrada\u0026rdquo; do sistema operacional precisaria ser escrita em Assembly. Procurando pela internet algo como \u0026ldquo;fazer um Hello World bootável\u0026rdquo;, ou como criar um programa que não precisa de sistema operacional para escrever algo na tela. Lembro-me que encontrei algo em C sobre um tal de endereço 0x800000 mas ficou por isso mesmo, na época o assunto estava muito além do que eu conseguia fazer facilmente e também não continuei aprendendo para entender como fazer algo.\nVindo para tempos mais atuais eu comecei a aprender um pouco mais sobre a linguagem Rust, que é uma linguagem que vem com o objetivo de cobrir alguns pontos de falha de C/C++ e também criada desde o inicio com aspectos modernos das linguagens atuais, um sistema de build e pacotes completo. Como a proposta dela é substituir essas duas linguagens citadas ela surge como uma alternativa para criação de drivers e até sistemas operacionais, além de permitir criação de aplicações mais comuns por ter algumas facilidades em relação a C/C++.\nNas pesquisas sobre Rust eu esbarrei em um conteúdo muito legal, chamado Writing an OS in Rust do Philipp Oppermann. O autor, utilizando Rust, passa por diversas etapas da criação de um sistema operacional, desde um simples Hello World! (como eu queria ter feito lá no inicio) até a criação de processamento assíncrono. Ele tem o cuidado de explicar cada etapa, ilustrar os conceitos e ensinar incrementalmente e ao final do processo você passa por diversos conceitos, como gerenciamento de memória, interrupções e muito mais. Além de ter criado esse blog (que confesso que para mim é praticamente um livro) ele também mantém diversas bibliotecas em Rust com funcionalidades básicas do sistema operacional.\nSistema operacional rodando dentro de um emulador (QEMU) O conteúdo é excelente, as explicações são claras mas confesso que me perdi em alguns momentos e reconheço que isso aconteceu por dois motivos: O primeiro é que não domino Rust ainda, a linguagem é bem fora do comum em alguns aspectos e para desenvolver o SO é necessário tocar em algumas coisas que não estão no básico da linguagem e apesar de ser bem cuidadoso e explicar muito bem os conceitos, o blog não esta feito para quem está aprendendo Rust. O segundo motivo é o conceito de sistema operacional em si, como foi a primeira vez que tive um contato com detalhes de implementação de algo assim as coisas não se fixaram tão bem, então é necessário uma revisão no futuro para eu dominar melhor o assunto. Mas ao final da jornada pelo blog eu confesso que aprendi muitas coisas e como o autor já divulgou que está trabalhando numa nova edição eu espero até lá estar mais apto para fazer novamente o tutorial.\nUm conteúdo muito interessante que ele cita no blog é o livro Three Easy Pieces dos autores Remzi H. Arpaci-Dusseau e Andrea C. Arpaci-Dusseau da Universidade de Winsconsin-Madson. O livro que está disponível online gratuitamente tem uma didática muito diferente da que estamos acostumados em outros textos sobre sistemas operacionais, utilizando programas simples para emular comportamentos do computador, como a priorização de tarefas, o livro consegue passar uma visão muito prática sobre como funciona um sistema operacional e já dá muitos insumos para conseguirmos implementarmos um.\nEXTRA: o endereço 0x800000 é o buffer da VGA, ou seja, o endereço para onde podemos mandar caracteres e escrever na tela, por isso eu vi ele anos atrás no Hello World que comentei no primeiro parágrafo.\n","permalink":"https://blog.lucaspolo.dev/posts/escrevendo-um-sistema-operacional-em-rust-de-philipp-opperman/","summary":"\u003cp\u003eEu me lembro que em 2008 eu imaginei como seria criar um sistema operacional e na época eu busquei algo na internet para fazer uma introdução no assunto. Eu lembro que a primeira coisa que imaginei foi que pelo menos a \u0026ldquo;entrada\u0026rdquo; do sistema operacional precisaria ser escrita em Assembly. Procurando pela internet algo como \u0026ldquo;fazer um Hello World bootável\u0026rdquo;, ou como criar um programa que não precisa de sistema operacional para escrever algo na tela. Lembro-me que encontrei algo em C sobre um tal de endereço \u003cstrong\u003e0x800000\u003c/strong\u003e mas ficou por isso mesmo, na época o assunto estava muito além do que eu conseguia fazer facilmente e também não continuei aprendendo para entender como fazer algo.\u003c/p\u003e","title":"Escrevendo um sistema operacional em Rust de Philipp Oppermann"},{"content":"Vira e mexe eu recebo alguns arquivos CSV que preciso fazer algum filtro ou alguma análise. Eu gosto muito de usar o Python para alguns processamentos, mas não é a coisa mais prática do mundo, ou abrir um script ou abrir um Jupyter Notebook para essa análise. Foi então que descobri que o DBeaver pode nos ajudar com este processo e é muito simples.\nApós abrirmos o DBeaver basta criarmos uma nova conexão e selecionarmos o diretório onde constará o(s) arquivo(s) CSV.\nAo terminar de configurar o drive de conexão será baixado e agora já podemos fazer queries normalmente usando SQL nos arquivos. É possível inclusive fazer join entre arquivos CSV diferentes, o que é mais difícil de fazer no Excel sem a utilização de formulas mais complexas.\n","permalink":"https://blog.lucaspolo.dev/posts/fazendo-queries-sql-em-arquivos-csv/","summary":"\u003cp\u003eVira e mexe eu recebo alguns arquivos CSV que preciso fazer algum filtro ou alguma análise. Eu gosto muito de usar o Python para alguns processamentos, mas não é a coisa mais prática do mundo, ou abrir um script ou abrir um Jupyter Notebook para essa análise. Foi então que descobri que o DBeaver pode nos ajudar com este processo e é muito simples.\u003c/p\u003e\n\u003cp\u003eApós abrirmos o DBeaver basta criarmos uma nova conexão e selecionarmos o diretório onde constará o(s) arquivo(s) CSV.\u003c/p\u003e","title":"Fazendo queries SQL em arquivos CSV"},{"content":"Durante o desenvolvimento é comum alterarmos o mesmo arquivo diversas vezes e se você gosta de manter um histórico consistente de suas alterações você pode esbarrar na situação onde um arquivo foi alterado em mais de um ponto e quer separar em commits distintos essas alterações.\nPra exemplificar este aqui é o código que iremos trabalhar:\nfrom collections import namedtuple Cliente = namedtuple(\u0026#39;Cliente\u0026#39;, \u0026#39;nome,idade\u0026#39;.split(\u0026#39;,\u0026#39;)) def inserir_cliente(cliente): print(f\u0026#39;Cliente {cliente.nome} inserido com sucesso\u0026#39;) return \u0026#39;ok\u0026#39; def test_inserir_cliente(): cliente = Cliente(\u0026#34;Monicão\u0026#34;, 3) resultado = inserir_cliente(cliente) assert resultado == \u0026#39;ok\u0026#39; Agora o que queremos fazer é adicionar uma função que verifica se o cliente é valido (o nome deverá ter mais de três caracteres e a idade deve ser um número maior ou igual a zero).\nfrom collections import namedtuple import pytest Cliente = namedtuple(\u0026#39;Cliente\u0026#39;, \u0026#39;nome,idade\u0026#39;.split(\u0026#39;,\u0026#39;)) def inserir_cliente(cliente): valida_cliente(cliente) print(f\u0026#39;Cliente {cliente.nome} inserido com sucesso\u0026#39;) return \u0026#39;ok\u0026#39; def valida_cliente(cliente): if len(cliente.nome) \u0026lt; 3 or cliente.idade \u0026lt; 0: raise ValueError(\u0026#34;O cliente é inválido\u0026#34;) def test_inserir_cliente(): cliente = Cliente(\u0026#34;Monicão\u0026#34;, 3) resultado = inserir_cliente(cliente) assert resultado == \u0026#39;ok\u0026#39; @pytest.mark.parametrize( \u0026#39;cliente\u0026#39;, [ Cliente(\u0026#39;Pô\u0026#39;, 2), Cliente(\u0026#39;Lala\u0026#39;, -1) ] ) def test_funcao_valida_cliente(cliente): with pytest.raises(ValueError): valida_cliente(cliente) Como podemos ver no cenário acima, a função valida_cliente foi criada e depois nós adicionamos na função inserir_cliente a chamada dessa função. O que queremos fazer aqui é criar um commit com a função valida_cliente e seus testes e no outro commit a alteração na função inserir_cliente e seus novos testes.\nSe utilizarmos os comandos que usamos mais comumente no nosso dia a dia iremos colocar todas as alterações em um único commit e entrega-las.\nDiferenças nos arquivos\nNo geral essa situação é comum, mas podem existir casos excepcionais onde teremos que fazer o procedimento onde criamos commits para as alterações em partes menores. Para conseguirmos fazer isso iremos utilizar o git add de maneira interativa, que irá abrir uma caixa de dialogo com diversas opções do que podemos realizar. Vamos executar o comando git add -i main.py\nIremos selelecionar a opção patch (digitando 5 ou \u0026ldquo;p\u0026rdquo;), após isso será apresentada a lista de arquivos que queremos atuar. Selecionamos nosso arquivo main.py com a opção 1 e agora podemos pressionar Enter para iniciar. Logo de cara todas as alterações serão oferecidas para inserirmos, porém não é isso que desejamos, então utilizando a opção s fazemos um split e então começará a ser oferecido pedaços de alterações para incluirmos ou recusarmos, com y e n respectivamente. O processo para o nosso arquivo foi feito conforme a gravação abaixo. Ao final dos pedaços de alteração que foram oferecido voltamos para o menu inicial e podemos pressionar 7 ou q para sair:\nProcesso de inclusão interativa de trechos do arquivo\nApós isso fiz o commit das alterações incluídas e realizando um git diff podemos ver que a inclusão da função de validação não foi feita, conforme queriamos, vamos reservar um commit só para ela:\nFazendo commit da alteração que falta Com isso concluímos o nosso trabalho e temos os commits organizados da maneira como planejamos lá no inicio. Essa ferramenta não é sempre necessária, porém pode ser muito útil quando precisamos organizar as alterações em um arquivo separando elas de maneira diferente na linha temporal do git.\nCaso tenha alguma sugestão ou dúvida não esqueça de utilizar os comentários. =)\n","permalink":"https://blog.lucaspolo.dev/posts/realizando-commits-parciais-no-git/","summary":"\u003cp\u003eDurante o desenvolvimento é comum alterarmos o mesmo arquivo diversas vezes e se você gosta de manter um histórico consistente de suas alterações você pode esbarrar na situação onde um arquivo foi alterado em mais de um ponto e quer separar em commits distintos essas alterações.\u003c/p\u003e\n\u003cp\u003ePra exemplificar este aqui é o código que iremos trabalhar:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e collections \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e namedtuple\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eCliente \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e namedtuple(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Cliente\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;nome,idade\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;,\u0026#39;\u003c/span\u003e))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003einserir_cliente\u003c/span\u003e(cliente):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Cliente \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003ecliente\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enome\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e inserido com sucesso\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ok\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003etest_inserir_cliente\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    cliente \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Cliente(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Monicão\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    resultado \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e inserir_cliente(cliente)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eassert\u003c/span\u003e resultado \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;ok\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAgora o que queremos fazer é adicionar uma função que verifica se o cliente é valido (o nome deverá ter mais de três caracteres e a idade deve ser um número maior ou igual a zero).\u003c/p\u003e","title":"Realizando commits parciais no Git"},{"content":"Este post é uma sequência deste outro post sobre os getters, vale apena conferi-lo antes.\nApós entendermos melhor como funcionam as propriedades em Python e aplicarmos os getters em nossa classe Circulo, ficamos com a pendência de entender como podemos agora aplicarmos os setters. O principio é muito similar e simples. Para isso basta definirmos o método em questão e decorá-lo com @nome_da_propriedade.setter.\nimport math class Circulo: def __init__(self, raio): self._raio = raio @property def raio(self): return self._raio @property def area(self): return self.raio ** 2 * math.pi @property def circunferencia(self): return self.raio * 2 * math.pi @raio.setter def raio(self, value): assert value \u0026gt; 0, \u0026#39;O valor do raio deve ser maior que 0\u0026#39; self._raio = value c = Circulo(5) print(c.area) c.raio = -1 Aproveitei também para já colocar uma validação no método e passei a utilizá-lo no método __init__. A criação é muito simples e prática, apesar de a API do setter não ser tão intuitiva, seu funcionamento é tão simples como a criação dos getters. Por se tratar um método podemos inclusive fazer outras computações nele, como por exemplo criar um setter para a área:\nimport math class Circulo: def __init__(self, raio): self.raio = raio @property def raio(self): return self._raio @property def area(self): return self.raio ** 2 * math.pi @property def circunferencia(self): return self.raio * 2 * math.pi @raio.setter def raio(self, value): assert value \u0026gt; 0, \u0026#39;O valor do raio deve ser maior que 0\u0026#39; self._raio = value @area.setter def area(self, value): assert value \u0026gt; 0, \u0026#39;A área deve ser maior que zero\u0026#39; self.raio = math.sqrt(value / math.pi) c = Circulo(5) print(c.area) c.area = 10 print(c.raio) Como podemos ver, definimos a partir da área o novo raio do circulo, também colocamos uma validação para os valores serem maiores que zero e conseguimos assim ter uma classe completa.\nComo em Python também podemos remover alguma propriedade usando a palavra reservada del, também podemos definir métodos que lidam com este comportamento. Como no exemplo abaixo:\nimport math class Circulo: def __init__(self, raio, cor=None): self.raio = raio self._cor = cor # Omitindo outros métodos @property def cor(self): return self._cor @cor.setter def cor(self, value): self._cor = value @cor.deleter def cor(self): self._cor = \u0026#34;transparente\u0026#34; c = Circulo(5, \u0026#34;vermelho\u0026#34;) del c.cor print(c.cor) Fazer esse tratamento para o del é algo muito interessante, podemos através deste método fazer muito mais coisas que apenas limpar uma propriedade, como por exemplo, realizar uma limpeza de outro recursos associados a propriedade (algo como um delete em cascata).\nA principal vantagem desse tratamento de propriedades no Python é o fato de podermos adicionar as validações posteriormente. Hoje em dia existem muitos outros tipos no Python para ajudar a carregar valores, como as dataclasses e as namedtuples, que valem muito apena serem estudadas, mas com certeza as propriedades ainda são muito utilizadas.\n","permalink":"https://blog.lucaspolo.dev/posts/o-jeito-pythonico-das-propriedades-no-python-parte-2/","summary":"\u003cp\u003eEste post é uma sequência \u003ca href=\"/posts/o-jeito-pythonico-das-propriedades-no-python-parte-1/\"\u003edeste outro post\u003c/a\u003e sobre os getters, vale apena conferi-lo antes.\u003c/p\u003e\n\u003cp\u003eApós entendermos melhor como funcionam as propriedades em Python e aplicarmos os \u003cem\u003egetters\u003c/em\u003e em nossa classe Circulo, ficamos com a pendência de entender como podemos agora aplicarmos os \u003cem\u003esetters.\u003c/em\u003e O principio é muito similar e simples. Para isso basta definirmos o método em questão e decorá-lo com \u003cstrong\u003e@nome_da_propriedade.setter\u003c/strong\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e math\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eCirculo\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003e__init__\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e, raio):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e_raio \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e raio\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @property\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eraio\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e_raio\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @property\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003earea\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio \u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epi\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @property\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003ecircunferencia\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epi\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    @raio.setter\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eraio\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e, value):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eassert\u003c/span\u003e value \u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;O valor do raio deve ser maior que 0\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003e_raio \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e value\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ec \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Circulo(\u003cspan style=\"color:#bd93f9\"\u003e5\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003earea)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ec\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAproveitei também para já colocar uma validação no método e passei a utilizá-lo no método \u003cem\u003e__init__\u003c/em\u003e. A criação é muito simples e prática, apesar de a API do setter não ser tão intuitiva, seu funcionamento é tão simples como a criação dos getters. Por se tratar um método podemos inclusive fazer outras computações nele, como por exemplo criar um setter para a área:\u003c/p\u003e","title":"O jeito pythonico das propriedades no Python - Parte 2"},{"content":"Eu sempre tive um pouco de dificuldade de assimilar as diferenças de código do jeito padrão do Git, que é feita da forma padrão do diff do GNU/Linux. É algo que vem muito com o hábito e em arquivos pequenos é até mais simples visualizar as diferenças:\nVisualização de diferença com o diff padrão\nA minha sorte foi que olhando algumas ferramentas feitas em Rust na internet eu esbarrei no Delta, que é uma ferramenta de diff que permite visualizar o arquivo de maneira muito mais rica.\nVisualização através do Delta, muito enriquecida\nTemos nele syntax highlight, visualização do arquivo lado a lado e diversas outras funcionalizades configuráveis, funcionando como um substituto para o utilitário diff e também como visualizador padrão de diferenças no Git.\nVisualização através do Delta com comparação de arquivos lado a lado O Delta pode ser encontrado no Github e você pode instalar de várias formas, confira em: https://github.com/dandavison/delta\n","permalink":"https://blog.lucaspolo.dev/posts/visualizando-diferencas-de-codigo-de-maneira-mais-simples-com-o-delta/","summary":"\u003cp\u003eEu sempre tive um pouco de dificuldade de assimilar as diferenças de código do jeito padrão do Git, que é feita da forma padrão do diff do GNU/Linux. É algo que vem muito com o hábito e em arquivos pequenos é até mais simples visualizar as diferenças:\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Saída do git diff padrão em example.lox, com as linhas removidas em vermelho e as adicionadas em verde, uma abaixo da outra\" loading=\"lazy\" src=\"/images/posts/visualizando-diferencas-de-codigo-de-maneira-mais-simples-com-o-delta/Screenshot_from_2021-08-18_11-27-40.png\"\u003e\n\u003cem\u003eVisualização de diferença com o diff padrão\u003c/em\u003e\u003c/p\u003e","title":"Visualizando diferenças de código de maneira mais simples com o Delta"},{"content":"Uma constante na orientação a objetos é a presença de propriedades dentro dos objetos quando precisamos armazenar dados para alguma manipulação posterior. É muito comum, principalmente quando viemos de outras linguagens, criarmos os famosos getters and setters para manter também um bom nível de encapsulamento. Vamos ter como exemplo a classe Circulo abaixo:\nimport math class Circulo: def __init__(self, raio): self.raio = raio def area(self): return self.raio ** 2 * math.pi def circunferencia(self): return self.raio * 2 * math.pi c = Circulo(1) print(c.raio) print(c.area()) print(c.circunferencia()) Perceba que para definirmos um círculo temos que passar o seu raio, com isso podemos calcular facilmente a sua área e circunferência. Precisamos também acessar ocasionalmente esse raio, podemos fazer isso através de dos getters que comentamos, mas isso não é o jeito do Python, ou como falaremos, o jeito mais Pythonico.\nO Python oferece um jeito de lidar melhor com propriedades de objetos e o acesso a elas através do decorador @property. Este decorador irá cobrir uma função com o nome da propriedade que precisamos acessar e permitirá que acessemos valores do objeto como se fossem propriedades:\nimport math class Circulo: def __init__(self, raio): self._raio = raio @property def raio(self): return self._raio def area(self): return self.raio ** 2 * math.pi def circunferencia(self): return self.raio * 2 * math.pi c = Circulo(1) print(c.raio) print(c.area()) print(c.circunferencia()) Dessa vez armazenamos a propriedade com o underscore na frente, indicando que a propriedade é privada. Após isso criamos um método chamado raioque retornará este valor e o decoramos com @property. O segredo aqui é que a forma de acesso ao raio não sofreu alteração, não quebrando assim o código que já acessa o raio do circulo.\nO mais legal é que esta funcionalidade não é apenas para propriedades armazenadas, como utilizamos o decorador em um método podemos utilizá-lo também em métodos que computam os valores, como o de área e circunferência:\nimport math class Circulo: def __init__(self, raio): self._raio = raio @property def raio(self): return self._raio @property def area(self): return self.raio ** 2 * math.pi @property def circunferencia(self): return self.raio * 2 * math.pi c = Circulo(1) print(c.raio) print(c.area) print(c.circunferencia) Agora acessamos os métodos que calculam algumas propriedades do circulo da mesma forma que acessamos as propriedades.\nEste é um ponto interessante sobre como Python lida com a orientação a objetos e cobre uma lacuna que muitas vezes é tratada de maneira dogmática (no caso a criação de getters) de uma forma mais simples, inclusive permitindo o acesso direto a propriedades em um primeiro momento, da maneira que fizemos no nosso primeiro exemplo, para um encapsulamento maior posteriormente sem quebrar as interfaces do nosso código.\nO outro lado dos getters, os famosos setters, iremos ver no próximo post junto com os deleters. Eles são muito fáceis e também demonstram a simplicidade criada para o programador devido uma interface de linguagem bem definida.\n","permalink":"https://blog.lucaspolo.dev/posts/o-jeito-pythonico-das-propriedades-no-python-parte-1/","summary":"\u003cp\u003eUma constante na orientação a objetos é a presença de propriedades dentro dos objetos quando precisamos armazenar dados para alguma manipulação posterior. É muito comum, principalmente quando viemos de outras linguagens, criarmos os  famosos getters and setters para manter também um bom nível de encapsulamento. Vamos ter como exemplo a classe \u003cem\u003eCirculo\u003c/em\u003e abaixo:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e math\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eCirculo\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003e__init__\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e, raio):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e raio\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003earea\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio \u003cspan style=\"color:#ff79c6\"\u003e**\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epi\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003ecircunferencia\u003c/span\u003e(\u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"font-style:italic\"\u003eself\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e*\u003c/span\u003e math\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epi\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ec \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Circulo(\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eraio)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003earea())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(c\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecircunferencia())\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePerceba que para definirmos um círculo temos que passar o seu raio, com isso podemos calcular facilmente a sua área e circunferência. Precisamos também acessar ocasionalmente esse raio, podemos fazer isso através de dos getters que comentamos, mas isso não é o jeito do Python, ou como falaremos, o jeito mais Pythonico.\u003c/p\u003e","title":"O jeito pythonico das propriedades no Python - Parte 1"},{"content":"Há algum tempo eu precisei mexer com as configurações de DNS no meu computador para conseguir utilizar o excelente projeto Pi Hole. Para quem não conhece, o Pi Hole é um projeto de servidor de DNS que possui uma lista de servidores de propaganda e bloqueia elas. Ele é excelente pois ao contrário dos Ad-Blockers ele não é tão facilmente detectável e como o bloqueio ocorre já na requisição de DNS ele também ajuda a economizar banda.\nMas voltando a minha aventura com o DNS, depois de alterar a configuração do DNS eu percebi que ainda estava recebendo anúncios que já deveriam ter sido bloqueados. Para saber qual o servidor de DNS eu utilizei o comando nslookup testando um site qualquer:\nPodemos ver na imagem algumas informações bem interessantes sobre o servidor de DNS que meu blog utiliza, mas o que me interessasva mesmo era saber qual era o DNS que eu estava utilizando no momento, sendo que me deparei com este IP descrito: 127.0.0.53. Como assim eu estava utilizando um IP da faixa de localhost?\nPesquisando na internet eu descobri que o Ubuntu por padrão utiliza o systemd-resolv como serviço de resolução de DNS, o que me deixou muito intrigado. Como é um serviço podemos inclusive consultar seu status através do comando sudo resolvectl status:\nAqui podemos tirar diversas informações, as que mais me interessavam eram os servidores DNS utilizados, na linha 44 do trecho acima. Como podemos ver, mesmo mudando o meu DNS no arquivo ele continuava utilizando o servidor antigo (no caso o meu roteador). Para isso então bastaria fazer um reload do serviço para carregar novamente o servidor.\nIsso para mim foi apenas o primeiro contato (pelo menos um primeiro contato consciente) que tive com o systemd. O systemd é um conjunto de programas que ajudam no gerenciamento dos recursos do sistema operacional, sendo muito conhecido e as vezes controverso pelo fato de ser algo tão grande que quer fazer diversas coisas ao mesmo tempo. De qualquer forma, é provável que você esteja usando ele, aprender como ele funciona é muito importante para um controle melhor do sistema operacional.\n","permalink":"https://blog.lucaspolo.dev/posts/minha-aventura-com-o-dns-no-ubuntu-meu-primeiro-contato-com-o-systemd/","summary":"\u003cp\u003eHá algum tempo eu precisei mexer com as configurações de DNS no meu computador para conseguir utilizar o excelente projeto Pi Hole. Para quem não conhece, o Pi Hole é um projeto de servidor de DNS que possui uma lista de servidores de propaganda e bloqueia elas. Ele é excelente pois ao contrário dos Ad-Blockers ele não é tão facilmente detectável e como o bloqueio ocorre já na requisição de DNS ele também ajuda a economizar banda.\u003c/p\u003e","title":"Minha aventura com o DNS no Ubuntu - meu primeiro contato com o systemd"},{"content":"O banco de dados é uma das partes mais importantes de qualquer aplicação e da mesma forma que as linguagens de programação que usamos, as vezes é necessário depurar o que está acontecendo dentro dele.\nUma das coisas que sempre devemos fazer ao digitar uma query nova que será utilizada pelo nosso programa é analisar o seu custo computacional no banco. Para conseguirmos fazer isso no PostgreSQL basta ativarmos uma diretriz antes da query (usaremos um banco de dados de filmes como exemplos que peguei aqui):\nEXPLAIN ANALYZE select * from film f inner join \u0026#34;language\u0026#34; l on f.language_id = l.language_id where l.\u0026#34;name\u0026#34; = \u0026#39;english\u0026#39;; Hash Join (cost=1.09..69.57 rows=167 width=480) (actual time=0.023..0.025 rows=0 loops=1) Hash Cond: (f.language_id = l.language_id) -\u0026gt; Seq Scan on film f (cost=0.00..64.00 rows=1000 width=384) (actual time=0.011..0.011 rows=1 loops=1) -\u0026gt; Hash (cost=1.07..1.07 rows=1 width=96) (actual time=0.008..0.008 rows=0 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 8kB -\u0026gt; Seq Scan on language l (cost=0.00..1.07 rows=1 width=96) (actual time=0.008..0.008 rows=0 loops=1) Filter: (name = \u0026#39;english\u0026#39;::bpchar) Rows Removed by Filter: 6 Planning Time: 0.196 ms Execution Time: 0.057 ms Como podemos ver o retorno da query acima deixou de ser os resultados da tabela propriamente dita e passou a ser a estratégia de execução da query. No caso aqui o que aconteceu foi primeiro um escaneamento sequêncial da tabela languages para depois fazer a junção com a tabela film através dos hashes gerados em cada operação.\nEssa análise já é completa, mas aprendendo mais sobre o significado dos resultados eu encontrei uma ferramenta excelente que ajuda a fazer uma análise mais visual do retorno do explain, este excelente site permite fazer uma análise mais gráfica e compartilhável da query.\nJá entrando no site podemos ver algumas instrução, primeiro é necessário acrescentarmos algumas diretivas no comando explain para formatar da maneira adequada para a leitura:\nEXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON) select * from film f inner join \u0026#34;language\u0026#34; l on f.language_id = l.language_id where l.\u0026#34;name\u0026#34; = \u0026#39;english\u0026#39;; Após isso também colamos a query sendo analisada (muito cuidado aqui para não expor nenhuma informação que você não deva) e podemos dar um título para nossa análise. Agora enviamos e recebemos um gráfico muito interessante sobre as etapas de execução, os índices utilizados e muitas informações.\nCada operação tem seus detalhes descrito em cada caixa Como podemos ver na imagem as coisas ficam bem mais interessantes de serem analisadas. Além de todas as informações que já tinhamos antes no modo de texto também temos explicações sobre cada operação, como a geração de hashes dos registros para fazer um hash join ao final da operação. Também temos informações sobre custos, tempos de cada etapa e muito mais. Além disso também é gerado um link compartilhável, para acessar o que utilizamos nesta análise você pode clicar aqui (lembre-se de não colocar informações sensíveis na sua query pois isso irá para a internet).\n","permalink":"https://blog.lucaspolo.dev/posts/analisando-queries-no-postgresql/","summary":"\u003cp\u003eO banco de dados é uma das partes mais importantes de qualquer aplicação e da mesma forma que as linguagens de programação que usamos, as vezes é necessário depurar o que está acontecendo dentro dele.\u003c/p\u003e\n\u003cp\u003eUma das coisas que sempre devemos fazer ao digitar uma query nova que será utilizada pelo nosso programa é analisar o seu custo computacional no banco. Para conseguirmos fazer isso no PostgreSQL basta ativarmos uma diretriz antes da query (usaremos um banco de dados de filmes como exemplos que peguei \u003ca href=\"https://www.postgresqltutorial.com/postgresql-sample-database/\"\u003eaqui\u003c/a\u003e):\u003c/p\u003e","title":"Analisando queries no PostgreSQL"},{"content":"Quando estudamos estatística é muito comum esbarrarmos no problema de Monty Hall. Monty Hall era um programa de TV onde o apresentador oferecia três portas para uma pessoa, atrás de uma delas havia um prêmio e das outras duas alguma coisa desagradável para dar o tom de humor do programa. Aqui no Brasil tinhamos o nosso equivalente apresentado pelo Sérgio Malandra, a Porta dos Desesperados. Aqui temos uma explicação do problema com sua solução:\nApesar da explicação do vídeo e de todas as outras que eu já vi, ainda pode ser um problema muito difícil de abstrair, então para testar a hipótese eu criei um script em R (linguagem de análise estatística que eu estudava na época) para simular o problema conforme as condições acima e realmente os resultados bateram, quando o candidato muda a porta na chance que o apresentador dá as chances de acerto sobem para 2/3. O script está abaixo:\ntentativas \u0026lt;- 100000 acertos_sem_troca \u0026lt;- 0 #INDICA QUE APESAR DO APRESENTADOR ABRIR UMA PORTA, ELA NAO TROCA troca = FALSE for(i in 1:tentativas) { portas \u0026lt;- c(1,2,3) porta_premiada \u0026lt;- sample(portas, 1, replace = FALSE) porta_escolhida \u0026lt;- sample(portas, 1, replace = FALSE) #O apresentador escolhe a porta sem premio e nao escolhida para abrir! portas_sem_premio \u0026lt;- portas[portas != porta_premiada] portas_spremio_nescolhida \u0026lt;- portas_sem_premio[portas_sem_premio != porta_escolhida] #Abrindo a Porta (removendo das possiblidades a porta que nao foi escolhida e nao eh a premiada) portas \u0026lt;- portas[!portas %in% portas_spremio_nescolhida] if(troca) { #Trocando porta escolhida pela outra porta porta_escolhida \u0026lt;- portas[1] } if(porta_escolhida == porta_premiada) { acertos_sem_troca = acertos_sem_troca + 1 } } acertos_com_troca \u0026lt;- 0 #INDICA QUE SERA TROCADO troca = TRUE for(i in 1:tentativas) { portas \u0026lt;- c(1,2,3) porta_premiada \u0026lt;- sample(portas, 1, replace = FALSE) porta_escolhida \u0026lt;- sample(portas, 1, replace = FALSE) #O apresentador escolhe a porta sem premio e nao escolhida para abrir! portas_sem_premio \u0026lt;- portas[portas != porta_premiada] portas_spremio_nescolhida \u0026lt;- portas_sem_premio[portas_sem_premio != porta_escolhida] #Abrindo a Porta (removendo das possiblidades a porta que nao foi escolhida e nao eh a premiada) portas \u0026lt;- portas[!portas %in% portas_spremio_nescolhida] if(troca) { #Trocando porta escolhida pela outra porta porta_escolhida \u0026lt;- portas[1] } if(porta_escolhida == porta_premiada) { acertos_com_troca = acertos_com_troca + 1 } } ","permalink":"https://blog.lucaspolo.dev/posts/o-problema-de-monty-hall-e-como-estatistica-nao-e-algo-intuitivo/","summary":"\u003cp\u003eQuando estudamos estatística é muito comum esbarrarmos no problema de Monty Hall. Monty Hall era um programa de TV onde o apresentador oferecia três portas para uma pessoa, atrás de uma delas havia um prêmio e das outras duas alguma coisa desagradável para dar o tom de humor do programa. Aqui no Brasil tinhamos o nosso equivalente apresentado pelo Sérgio Malandra, a Porta dos Desesperados. Aqui temos uma explicação do problema com sua solução:\u003c/p\u003e","title":"O problema de Monty Hall e como estatística não é algo intuitivo"},{"content":"Este post é uma continuidade dos posts Lendo arquivos CSV em Python e fazendo requisições e do post Fazendo requests concorrentemente (assíncronas) no Python\nApós fazermos as requests assíncronas no último post obtivemos uma melhoria signifcativa em nosso processamento, conseguindo paralelizar as requests e reduzindo muito o tempo. Porém não estamos fazendo o melhor proveito da API async do Python, percebam que cada função async também é responsável por também imprimir o resultado e o ideal seria retornarmos os resultados para tratar posteriormente. Vamos fazer isso:\nasync def process_register(register): async with httpx.AsyncClient() as client: response = await client.put( url=f\u0026#39;https://teste-api-async.free.beeceptor.com/clientes/{register[\u0026#34;id\u0026#34;]}\u0026#39;, json={ \u0026#39;nome\u0026#39;: register[\u0026#39;nome\u0026#39;] } ) status_code = response.status_code # Adicionei um pequeno tratamento de erro caso o status_code não seja 200 return status_code, response.json() if status_code == 200 else {\u0026#39;result\u0026#39;: \u0026#39;error\u0026#39;} A mudança foi bem sútil, apenas começamos a retornar o código de status da requisição e o payload. Agora na nossa função main precisamos receber estes resultados e iterar sobre eles.\nasync def main(): with open(\u0026#39;arquivo.csv\u0026#39;) as f: reader = csv.DictReader(f) tasks = set() for register in reader: tasks.add( asyncio.create_task(process_register(register)) ) done, pending = await asyncio.wait(tasks) Veja que agora passarmos armazenar o resultado de nossa função em duas variáveis, done e pending. Na variável done estão todas as tasks que foram concluídas e na pending as que ainda não terminaram, como por padrão a função asyncio.wait espera todas concluirem a variável pending sempre retornará um conjunto vazio. Agora o que precisamos fazer é iterar sobre os resultados retornados e fazer o processamento necessário sobre eles:\nasync def main(): with open(\u0026#39;arquivo.csv\u0026#39;) as f: reader = csv.DictReader(f) tasks = set() for register in reader: tasks.add( asyncio.create_task(process_register(register)) ) done, pending = await asyncio.wait(tasks) for task in done: print(task.result()) # Começamos a consumir os resultados aqui! No código acima iteramos sobre as tasks e passamos vamos coletando todos os resultados através do método .result(). Com isto já temos como processar diversos resultados de uma vez. O único ponto aqui é que como disparamos todas as requisições do nosso CSV de uma vez, pode acontecer de sermos bloqueados pelo serviço (imagine que o CSV tenha vinte mil registros), ou até pior, poderíamos derrubar o serviço em questão como se fosse um ataque DoS. Resolver isso é bem simples, podemos dividir nossa lista em pedaços de cinco (para isso vou utilizar o código deste post do Stackoverflow que deve ser o trecho de código de três linhas mais copiado da história, risos) de tamanho fixo para realizar este processamento e acumular os resultados para o final:\ndef chunks(lst, n): \u0026#34;\u0026#34;\u0026#34;Retorna um iterador de listas dividindo a lista original em pedaços\u0026#34;\u0026#34;\u0026#34; for i in range(0, len(lst), n): yield lst[i:i + n] async def main(): with open(\u0026#39;arquivo.csv\u0026#39;) as f: reader = csv.DictReader(f) registers = list(reader) # Como vamos quebrar em lista menores, vamos converter antes em uma lista processed = [] for chunk in chunks(registers, 5): tasks = set() for register in chunk: print(register) tasks.add( asyncio.create_task(process_register(register)) ) done, pending = await asyncio.wait(tasks) for task in done: processed.append(task.result()) # Armazenamos o resultado em uma lista for p in processed: # Exibimos quando conluir tudo print(p) Com isso agora temos um script que faz o processamento em paralelo porém sem oferecer riscos para o serviço que estamos chamando. Podemos aumentar o número de requisições em paralelo de acordo com o serviço e também podemos salvar os resultados em outro arquivo, o que vai depender da sua necessidade, mas o que fizemos até aqui já é uma base que permite criar scripts muito úteis e também aprendemos a utizar as bibliotecas async do Python para fazer requisições em paralelo, podendo utilizar estes conceitos de diversas outras formas.\n","permalink":"https://blog.lucaspolo.dev/posts/melhorando-as-requisicoes-assincronas-com-python-parte-3/","summary":"\u003cp\u003eEste post é uma continuidade dos posts \u003ca href=\"/posts/lendo-arquivos-csv-em-python-e-fazendo-requisicoes-parte-1/\"\u003eLendo arquivos CSV em Python e fazendo requisições\u003c/a\u003e e do post \u003ca href=\"/posts/fazendo-requests-concorrentemente-assincronas-no-python-parte-2/\"\u003eFazendo requests concorrentemente (assíncronas) no Python\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eApós fazermos as requests assíncronas no último post obtivemos uma melhoria signifcativa em nosso processamento, conseguindo paralelizar as requests e reduzindo muito o tempo. Porém não estamos fazendo o melhor proveito da API async do Python, percebam que cada função async também é responsável por também imprimir o resultado e o ideal seria retornarmos os resultados para tratar posteriormente. Vamos fazer isso:\u003c/p\u003e","title":"Melhorando as requisições assíncronas com Python - Parte 3"},{"content":"As vezes precisamos executar scripts grandes, como inserir uma massa de dados muito grande ou fazer diversas queries ao mesmo tempo. As ferramentas de bancos de dados ajudam muito nisso, mas as vezes o script pode ser tão grande que a ferramenta não aguenta e pode encher muito a memória (caso que aconteceu comigo recentemente onde o DBeaver tinha onze mil inserts para fazer).\nFelizmente existe uma ferramenta de linha de comando muito prática chamada psql, ele é mantido também pelas mesmas pessoas do PostgreSQL e é muito eficiente. O psql é um utilitário de linha de comando que permite executar comandos no banco de dados e também executar scripts em lote. Um exemplo de execução poderia ser assim:\npsql -h localhost -d banco_de_dados -u usuario -f=arquivo.sql\nCom este simples comando já é possível rodar scripts intensos no banco de dados. Existem muito mais opções disponíveis que vale apena conferir no manual, como por exemplo extrair a saída em HTML, rodar os comandos um a um para análises e muito mais.\n","permalink":"https://blog.lucaspolo.dev/posts/executando-scripts-no-banco-postgresql-com-o-psql/","summary":"\u003cp\u003eAs vezes precisamos executar scripts grandes, como inserir uma massa de dados muito grande ou fazer diversas queries ao mesmo tempo. As ferramentas de bancos de dados ajudam muito nisso, mas as vezes o script pode ser tão grande que a ferramenta não aguenta e pode encher muito a memória (caso que aconteceu comigo recentemente onde o DBeaver tinha onze mil inserts para fazer).\u003c/p\u003e\n\u003cp\u003eFelizmente existe uma ferramenta de linha de comando muito prática chamada \u003ca href=\"https://www.postgresql.org/docs/9.2/app-psql.html\"\u003e\u003cstrong\u003epsql\u003c/strong\u003e\u003c/a\u003e, ele é mantido também pelas mesmas pessoas do PostgreSQL e é muito eficiente. O \u003cstrong\u003epsql\u003c/strong\u003e é um utilitário de linha de comando que permite executar comandos no banco de dados e também executar scripts em lote. Um exemplo de execução poderia ser assim:\u003c/p\u003e","title":"Executando scripts no banco PostgreSQL com o psql"},{"content":"Durante o desenvolvimento é muito comum encontrarmos alterações para fazermos em arquivos que já foram alterados e não estão mais no último PR. Para não gerar um grande número commits de ajustes pequenos podemos reorganizar estas alterações utilizando o rebase interativo.\nPreciso deixar apenas um aviso importante, como alteramos a ordem dos commits isso irá gerar uma reescrita de histórico de commits, assim caso você já tenha feito o push da versão anterior para uma branch remota será necessário refazer o procedimento com o famigerado \u0026ndash;force, o que pode trazer perdas de commits caso essa branch esteja sendo usada por outra pessoa, outro ponto, evite fazer reescrita de histórico na branch principal do projeto.\nVamos considerar o seguinte cenário: temos um pequeno projeto, primeiro eu iniciei o repositório e criei um arquivo README.md e commitei, depois criei as funções utilitárias no módulo lib.js e commitei. Por último criei o main.js para que chamará a função em questão. Todas as alterações ainda estão na minha máquina e não mergeei na master remota. A estrutura ficou como a imagem abaixo:\nEstrura de arquivos e os três commits iniciais Após isso percebi que é necessário fazer uma correção no arquivo lib.js. A primeira coisa que faço então é esta alteração e commito ela: Agora o fix está como o último commit Partindo do principio que esta correção era necessária, podemos entender que todos os commits desde a criação da biblioteca de funções lib.js até a correção possuem um bug e estão quebrados. Como estas alterações ainda estão na minha branch, porque não podemos organizar isso melhor? Ai entra o rebase interativo.\nO rebase interativo permite reorganizar nossos commits, alterar mensagens e diversas outras coisas, para iniciar o processo no Git é muito simples, basta você rodar o comando git rebase -i HEAD~3, traduzindo: inicie o rebase interativo a partir de três commits a partir da HEAD (o último commit). Ao executar temos a seguinte tela:\nTemos a lista de commits e um manual do que temos disponível no rebase A janela que abre contém a lista de commits e algumas instruções do que podemos fazer. No nosso caso queremos juntar o commit Fix na lib.js com o commit Criada lib de funções, para isso vamos fazer duas coisas, reordernar os commits e pedir para fazer um fixupno commit de fix, ficando: Os commits foram reordenados pedimos para aplicar fixup no commit de fix O comando fixup irá fundir o commit de sua linha com o de cima (no caso o commit mais antigo), juntando as alterações em um único commit. Agora podemos salvar e sair para assim o rebase prosseguir até o fim: Rebase aplicado e commits organizados Após isso os commits estarão mais organizados, isso ajudará você a navegar melhor pelo seu histórico de commits, ajudará também os revisores que poderão fazer o review por commits e não ficar pescando trechos de códigos em diversos commits diferentes.\n","permalink":"https://blog.lucaspolo.dev/posts/adicionando-alteracoes-em-commits-antigos-com-o-rebase-interativo/","summary":"\u003cp\u003eDurante o desenvolvimento é muito comum encontrarmos alterações para fazermos em arquivos que já foram alterados e não estão mais no último PR. Para não gerar um grande número commits de ajustes pequenos podemos reorganizar estas alterações utilizando o rebase interativo.\u003c/p\u003e\n\u003cp\u003ePreciso deixar apenas um aviso importante, como alteramos a ordem dos\ncommits isso irá gerar uma reescrita de histórico de commits, assim caso\nvocê já tenha feito o push da versão anterior para uma branch remota\nserá necessário refazer o procedimento com o famigerado \u003cstrong\u003e\u0026ndash;force\u003c/strong\u003e, o\nque pode trazer perdas de commits caso essa branch esteja sendo usada\npor outra pessoa, outro ponto, \u003cstrong\u003eevite fazer reescrita de histórico na\nbranch principal do projeto\u003c/strong\u003e.\u003c/p\u003e","title":"Adicionando alterações em commits antigos com o rebase interativo"},{"content":"Comecei a trabalhar recentemente com Node.js e estou curtindo bastante as particularidades dele. Além do Javascript existe todo um mundo de conceitos por trás do Node.js, na forma como ele foi construido e sua arquitetura.\nA único \u0026ldquo;defeito\u0026rdquo; do Node.js para mim, que na verdade é algo do Javascript, é que se você for iniciante em programação logo de cara terá que lidar com a questão de programação concorrente, eventos e coisas um pouco mais complexas, o que em outras linguagens muitas vezes ficam para um segundo momento serem aprendidas.\nUm conteúdo que me ajudou muito a entender o modelo de concorrência do Javascript e como ele funciona por debaixo dos panos é a série de artigos Node.js por Baixo dos Panos do Lucas Santos. Recomendo muito a leitura, principalmente se você já se sente mais confortável com o Javascript e quer dar um passo além.\n","permalink":"https://blog.lucaspolo.dev/posts/achados-aprendendo-node-js/","summary":"\u003cp\u003eComecei a trabalhar recentemente com Node.js e estou curtindo bastante as particularidades dele. Além do Javascript existe todo um mundo de conceitos por trás do Node.js, na forma como ele foi construido e sua arquitetura.\u003c/p\u003e\n\u003cp\u003eA único \u0026ldquo;defeito\u0026rdquo; do Node.js para mim, que na verdade é algo do Javascript, é que se você for iniciante em programação logo de cara terá que lidar com a questão de programação concorrente, eventos e coisas um pouco mais complexas, o que em outras linguagens muitas vezes ficam para um segundo momento serem aprendidas.\u003c/p\u003e","title":"Achados: aprendendo Node.js"},{"content":"Este post é uma continuação direta do post Lendo arquivos CSV em Python e fazendo requisições - Parte 1\nDepois de conseguirmos ler o CSV e conseguirmos fazer requisições em lote, podemos agora iniciar uma primeira otimização, realizar as cotações em paralelo. Para isto usaremos a API assíncrona do Python em conjunto com uma nova biblioteca de requests, a HTTPX.\nA primeira coisa que faremos é alterar a biblioteca Python que utilizamos, adaptar a requisição e nosso programa para começar a trabalhar assíncronamente. As alterações são principalmente na definição das funções e também nas mudanças para as chamadas das funções assíncronas que agora precisam do await antes:\nimport asyncio import csv import httpx async def process_register(register): async with httpx.AsyncClient() as client: response = await client.put( url=f\u0026#39;http://httpbin.org/200/{register[\u0026#34;id\u0026#34;]}/\u0026#39;, json={ \u0026#39;nome\u0026#39;: register[\u0026#39;nome\u0026#39;] } ) print(response.text) async def main(): with open(\u0026#39;arquivo.csv\u0026#39;) as f: reader = csv.DictReader(f) for register in reader: await process_register(register) Após isso também precisamos rodar o novo main assíncrono através de um EventLoop. Python possui diversos modelos de concorrência e paralelismo, o que usaremos aqui são as corrotinas, que são rotinas que funcionam de maneira cooperativa, isto é, quando uma função chega num ponto onde ela aguardará um determinado tempo ela cede a execução do interpretador para outras atividades. No Python essa concessão ocorrerá em momentos de entrada e saída de dados, como a leitura de um arquivo, acesso a um banco de dados ou, como nosso caso, a requisição de uma API web. Uma explicação simples como funcionam as corrotimas pode ser vista aqui.\nif __name__ == \u0026#39;__main__\u0026#39;: asyncio.run(main()) \u0026ldquo;Legal Lucas, mas executei aqui e ainda está executando uma request de cada vez!\u0026rdquo;\nSim, este é um ponto, mesmo já utilizando a API async do Python, nosso código ainda não está executando as requests concorrentemente. Para isso precisamos preparar as corrotinas, convertendo elas em tarefas (tasks) e executa-las concorrentemente através de uma API oferecida para o Python:\nasync def main(): with open(\u0026#39;arquivo.csv\u0026#39;) as f: reader = csv.DictReader(f) tasks = set() for register in reader: tasks.add( asyncio.create_task(process_register(register)) ) await asyncio.wait(tasks) Agora as coisas ficaram bem mais interessantes, quando executamos percebemos que simplesmente é disparado na tela todos as impressões de retorno uma única vez e fora de ordem.\nPodemos também fazer uma comparação de tempo de execução da versão síncrona e da versão assíncrona:\n(.venv) tux@tux-desktop:~/Projects/Tests/csv_python$ time python sincrona.py Processado registro 1 Processado registro 2 Processado registro 3 Processado registro 4 Processado registro 5 Processado registro 6 Processado registro 7 real\t0m2,173s user\t0m0,206s sys\t0m0,009s (.venv) tux@tux-desktop:~/Projects/Tests/csv_python$ time python assincrona.py Processado registro 6 Processado registro 2 Processado registro 5 Processado registro 4 Processado registro 3 Processado registro 7 Processado registro 1 real\t0m0,463s user\t0m0,172s sys\t0m0,016s Perceba que a diferença de tempo é absurda, sendo 2.17 segundos na versão síncrona contra 0.46 segundos na versão assíncrona. Mas ai você se pergunta: \u0026ldquo;Por que então não fazemos tudo assíncrono e em paralelo?\u0026rdquo;. Essa é uma pergunta simples com uma resposta difícil, várias coisas entram em jogo quando começamos a realizar operações assíncronas, só vou citar uma delas para inicio de conversa, a memória. Com todas estas operações sendo executadas concorrentemente o computador armazena todos os estados em memória ao mesmo tempo, ao contrário da execução síncrona que executa uma vez, libera memória e vai para o próximo processamento. Existem tópicos sobre essa questão ainda muito mais críticos, como as condições de corrida (racing conditions), mas não é o objetivo aqui se estender neste assunto nesta séries de posts.\nAinda podemos adicionar um controle mais fino desse processamento em paralelo, como executar em lotes o processamento para não sobrecarregar o servidor que estamos chamando e nem a nossa máquina. Vamos tentar fazer isso num próximo post, além de alguns últimos acréscimos interessantes.\n","permalink":"https://blog.lucaspolo.dev/posts/fazendo-requests-concorrentemente-assincronas-no-python-parte-2/","summary":"\u003cp\u003eEste post é uma continuação direta do post \u003ca href=\"/posts/lendo-arquivos-csv-em-python-e-fazendo-requisicoes-parte-1/\"\u003eLendo arquivos CSV em Python e fazendo requisições - Parte 1\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eDepois de conseguirmos ler o CSV e conseguirmos fazer requisições em lote, podemos agora iniciar uma primeira otimização, realizar as cotações em paralelo. Para isto usaremos a API assíncrona do Python em conjunto com uma nova biblioteca de requests, a \u003ca href=\"https://www.python-httpx.org/\"\u003eHTTPX\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eA primeira coisa que faremos é alterar a biblioteca Python que utilizamos, adaptar a requisição e nosso programa para começar a trabalhar assíncronamente. As alterações são principalmente na definição das funções e também nas mudanças para as chamadas das funções assíncronas que agora precisam do \u003cem\u003eawait\u003c/em\u003e antes:\u003c/p\u003e","title":"Fazendo requests concorrentemente (assíncronas) no Python - Parte 2"},{"content":"Já faz algum tempo em que estou interessado a aprender a desenvolver jogos, apenas por diversão e aprendizado mesmo. A área de desenvolvimento de jogos tem algumas coisas muito diferentes do desenvolvimento que estou acostumado, por exemplo, em alguns momentos é comum carregar tudo na memória no inicio da execução para depois só ir exibindo, algo que as vezes pode ser dispendioso em um programa que precisa atender diversas requisições o mais rápido possível.\nA pouco tempo escrevi uma resenha sobre um livro que curti muito para quem está querendo começar a aprender os algoritmos básicos de desenvolvimento de jogos, você pode ler mais sobre ela aqui.\nDando continuidade ao aprendizado eu fiz um curso de desenvolvimento de jogos com Lua na Alura. O curso segue a mesma linha do livro, é bem básico mas passa pelos conceitos de uma maneira mais rápida, falando menos sobre os detalhes dos conceitos, mas ainda assim consegue passar por todos eles. No inicio ele aborda os conceitos básicos da linguagem Lua, muito utilizada em diversos lugares, principalmente como uma linguagem de script para programas escritos em outras linguagens. Após essa introdução já é iniciado o desenvolvimento do jogo com a biblioteca LÖVE, que é capaz de fornecer todo o framework básico para lidar com imagens, sons e também o esqueleto básico de um jogo, como o game loop.\nDesta vez foi desenvolvido um jogo de avião tipo arcade em que precisamos destruir meteóros que aparecem na tela. O legal de fazer este curso após ter lido o livro de GameDev é que os conceitos se firmam de maneira muito mais simples e temos agora um framework básico para ajudar com alguns pontos, ao contrário do livro que se propunha a repassar por estes conceitos para termos um primeiro contato.\n14Bis vs Meteoros: Santos Dummont não esperava por essa Desenvolver este jogo foi muito divertido e mais uma vez tomei a liberdade de fazer algumas escolhas que iam em outros caminhos apresentados pelo curso, acrescentando umas funcionalidades básicas. O desenvolvimento de jogos é uma área incrível e o que mais me fascina é que seu conjunto de práticas as vezes vai contra o que pregamos no dia a dia do desenvolvimento mais comum, ajudando assim a expandir cada vez mais os nossos conhecimentos.\n","permalink":"https://blog.lucaspolo.dev/posts/aprendendo-a-desenvolver-jogos/","summary":"\u003cp\u003eJá faz algum tempo em que estou interessado a aprender a desenvolver jogos, apenas por diversão e aprendizado mesmo. A área de desenvolvimento de jogos tem algumas coisas muito diferentes do desenvolvimento que estou acostumado, por exemplo, em alguns momentos é comum carregar tudo na memória no inicio da execução para depois só ir exibindo, algo que as vezes pode ser dispendioso em um programa que precisa atender diversas requisições o mais rápido possível.\u003c/p\u003e","title":"Aprendendo a desenvolver jogos"},{"content":"Recentemente tirei uma certificação de analista de infraestrtura da minha mesa! 😂\nPiadas a parte, consegui deixar minha mesa de trabalho muito organizada utilizando alguns acessórios bem diferentes. Possuo dois computadores, sendo um notebook do trabalho e o meu desktop onde estudo, programo e jogo. Além dos computadores tenho dois monitores na minha mesa, um na vertical que costumo trabalhar dividido em dois (muito útil para deixar chats abertos) e outro widescreen (que também costuma trabalhar dividido) na horizontal.\nPrimeiramente eu poderia deixar apenas o desktop ligado nos monitores e usar o notebook apenas con a tela dele, mas eu já teria dois problemas, precisaria tirar o teclado e o mouse da mesa e também não conseguiria tirar vantagens dos monitores externos. Para resolver o problema bastou eu ligar as saídas extras dos monitores (ambos possuem dois HDMIs e uma DisplayPort) no notebook, porém o notebok possui apenas uma saída HDMI, ai entrou em cena o primeiro acessório, um adaptador USB-C para HDMI/USB C/USB A, permitindo assim ligar um cabo HDMI direto no notebook e outro no adaptador. Depois disso tudo consigo utilizar o desktop ligados nas Displayports dos monitores e o notebook ligado pelas portas HDMIs, bastando selecionar nos próprios monitores qual desejo utilizar no momento.\nNo desktop surge a necessidade de usar um teclado e mouse externos, porém o teclado e o mouse ficam na frente do monitor e se eu quiser usar o notebook precisaria tirar eles, deixando a mesa bagunçada. Para facilitar isso eu poderia deixar o notebook fechado e usar os mesmos teclados e mouse nele, porém para isso eu teria que ficar tirando o teclado e mouse do desktop e colocando no notebook, o que é chato pois os dois acessórios ficam conectados atrás do desktop além do desgaste que isso iria gerar nos conectores. Para resolver esse problema eu encontrei um acessório muito legal, um switch USB. Ele possui duas saídas que vão para o desktop e o notebook e quatro entradas onde ligo o mouse, o teclado e outros acessórios. Apesar de simples esse é o principal acessório de todo o conjunto, pois quando quero alternar entre o desktop e o notebook basta eu pressionar um botão neste switch.\nEsse cara que foi o pulo do gato para deixar as coisas organizadas Com isso eu já consigo utilizar ambos os computadores com os mesmos monitores, teclado e mouse, bastando alternar quando necessário. Aproveitei esta configuração para deixar o notebook fechado e para liga-lo eu utilizo um recurso muito interessante, o Wake On Lan, que permite que o computador ligue quando envio um pacote específico pela rede, algo que é feito pelo meu smartphone ou até pela Alexa.\nPara fechar o setup eu só tinha um problema para resolver, o Wake On Lan só funciona através da rede cabeada, por isso o cabo de rede que ia para o desktop começou a fica no notebook (o que não teria grandes problemas, pois o desktop possui WiFi), mas como gosto de utilizar cabos de rede eu precisava puxar mais um cabo do roteador até a mesa, o que não é muito conveniente. Para me salvar dessa situação eu comprei um pequeno switch de rede que recebe a internet do roteador e distribui para o desktop e notebook, sem perder performance e com a latência igual a ligação direta.\nPara organizar tudo isso foi simples, prendi o switch USB e o de rede embaixo da minha mesa utilizando velcro, assim caso necessário posso remove-los para alguma manutenção. Para os cabos não ficarem pendurados eu usei presilhas também presas na mesa e uma cestinha fixada na mesa que ajuda a segurar as fontes do notebook e do monitor.\nCada acessório custa em média R$ 80, mas é comum encontrar até por menos em alguns sites, fechando próximo dos R$ 250 todo o conjunto.\n","permalink":"https://blog.lucaspolo.dev/posts/a-infraestrutura-da-minha-mesa/","summary":"\u003cp\u003eRecentemente tirei uma certificação de analista de infraestrtura da minha mesa! 😂\u003c/p\u003e\n\u003cp\u003ePiadas a parte, consegui deixar minha mesa de trabalho muito organizada utilizando alguns acessórios bem diferentes. Possuo dois computadores, sendo um notebook do trabalho e o meu desktop onde estudo, programo e jogo. Além dos computadores tenho dois monitores na minha mesa, um na vertical que costumo trabalhar dividido em dois (muito útil para deixar chats abertos) e outro widescreen (que também costuma trabalhar dividido) na horizontal.\u003c/p\u003e","title":"A infraestrutura da minha mesa"},{"content":"Talvez você não conheça, mas Edsger W. Dijkstra é um dos nomes mais proeminentes da história da ciência da computação, sendo uma das pessoas que trabalhou na área ainda nos primeiros protótipos de computadores. Caso você tenha estudado algoritmos já deve ter esbarrado no algoritmo de Dijkstra, que é para encontrar o menor caminho em grafos, mas caso ainda não tenha esbarrado em nenhum trabalho dele, vale apena conhecer este artigo (em inglês) em que ele explica por que a número em sequências numéricas deve iniciar em zero, artigo indicado no excelente livro Python Fluente do Luciano Ramalho.\nBasicamente ele junta alguns argumentos que mostram as facilidades de iniciarmos em zero as sequências e termos o termo finalizador exclusivo, como a sequência [0,1,2,3,4] que é denotada como 0 ≤ x \u0026lt; 5. O artigo é bem simples, mas é interessante como um dos homens mais geniais na ciência da computação argumenta de uma maneira quase que informal sobre algo que está presente no nosso dia a dia.\n\u0026ldquo;Se debugar é o processo de remover bugs no software, programar é o processo de colocar bugs\u0026rdquo; - Edsger Dijkstra\n","permalink":"https://blog.lucaspolo.dev/posts/pequeno-achado-por-que-numeracao-deve-iniciar-em-zero-de-edsger-dijkstra/","summary":"\u003cp\u003eTalvez você não conheça, mas Edsger W. Dijkstra é um dos nomes mais proeminentes da história da ciência da computação, sendo uma das pessoas que trabalhou na área ainda nos primeiros protótipos de computadores. Caso você tenha estudado algoritmos já deve ter esbarrado no algoritmo de Dijkstra, que é para encontrar o menor caminho em grafos, mas caso ainda não tenha esbarrado em nenhum trabalho dele, vale apena conhecer \u003ca href=\"https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html\"\u003eeste artigo\u003c/a\u003e (em inglês) em que ele explica por que a número em sequências numéricas deve iniciar em zero, artigo indicado no excelente livro \u003ca href=\"https://novatec.com.br/livros/pythonfluente/\"\u003ePython Fluente do Luciano Ramalho\u003c/a\u003e.\u003c/p\u003e","title":"Pequeno achado: Por que numeração deve iniciar em zero? De Edsger Dijkstra"},{"content":"Algumas vezes surge a necessidade de fazermos algum processamento em uma base de dados, como requisições e afins. É muito comum neste momento recebermos um CSV ou até mesmo uma planilha do Excel, ai neste momento devemos escrever um script que processe essa informação. Suponhamos que precisamos atualizar o nome de algum cliente dado seus id\u0026rsquo;s e nomes, seguindo um arquivo neste modelo:\nid,nome 1,Cebolinha 2,Monica 3,Magali 4,Cascão 5,Penadinho 6,Alminha 7,Horácio A abordagem mais simples que eu sigo é iniciar criando uma função primária, que no geral chamo de main e iterar no arquivo CSV usando um DictReader:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import csv def process_register(register): print(f\u0026#39;ID: {register[\u0026#34;id\u0026#34;]}, nome: {register[\u0026#34;nome\u0026#34;]}\u0026#39;) def main(): with open(\u0026#39;arquivo.csv\u0026#39;) as f: reader = csv.DictReader(f) for register in reader: process_register(register) if __name__ == \u0026#39;__main__\u0026#39;: main() Como pode ser visto, na linha 9 abrimos um arquivo utilizando um gerenciador de contexto, que tem a vantagem de fechar o arquivo automaticamente ao sair do escopo do with.\nApós isso na linha 10 criamos um DictReader que é um leitor de CSV que tem a vantagem de ao ler o arquivo CSV gerar registros em forma de dicionários, permitindo acessarmos seus campos pela chave do CSV: register[\u0026lsquo;id\u0026rsquo;], por exemplo, ao invés de registro[0] (porém é importante destacar que para isso o arquivo deve possuiir cabeçalho com o nome dos campos ou você deve passar na chamada do DictReader uma lista com os nomes dos campos, vide documentação aqui).\nUma vantagem dessa abordagem é que tudo ocorre utilizando iteradores, que ao invés de carregar todo o arquivo em memória para processa-lo, acessa linha a linha o arquivo faz o processamento individual. Quando executarmos o script já obteremos o seguinte resultado:\nJá com este esqueleto principal montado podemos seguir com a parte de requisição, para isso podemos usar uma biblioteca de requisições como a requests. Basta colocarmos a importação da biblioteca e o código em questão na função process_register:\nimport csv import requests def process_register(register): response = requests.put( url=f\u0026#39;https://teste-api-async.free.beeceptor.com/clientes/{register[\u0026#34;id\u0026#34;]}/\u0026#39;, json={ \u0026#39;nome\u0026#39;: register[\u0026#39;nome\u0026#39;] } ) print(response.text) Com isso já temos um script básico para fazer requisições em lote, caso o retorno seja um json ao invés de response.text podemos usar um response.json(). Podemos substituir a chamada de uma API para uma atualização em um banco de dados ou até mesmo a geração de outro arquivo, além de melhorias como controle de reprocessamento usando um banco SQLite (que já vem com o drive nativamente no Python) ou melhorar a performance utilizando funções assíncronas e fazer as requisições concorrentemente.\n","permalink":"https://blog.lucaspolo.dev/posts/lendo-arquivos-csv-em-python-e-fazendo-requisicoes-parte-1/","summary":"\u003cp\u003eAlgumas vezes surge a necessidade de fazermos algum processamento em uma base de dados, como requisições e afins. É muito comum neste momento recebermos um CSV ou até mesmo uma planilha do Excel, ai neste momento devemos escrever um script que processe essa informação. Suponhamos que precisamos atualizar o nome de algum cliente dado seus \u003cem\u003eid\u0026rsquo;s\u003c/em\u003e e nomes, seguindo um arquivo neste modelo:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-csv\" data-lang=\"csv\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003eid\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003enome\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e1\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003eCebolinha\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e2\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003eMonica\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e3\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003eMagali\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e4\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003eCascão\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e5\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003ePenadinho\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e6\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003eAlminha\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e7\u003c/span\u003e,\u003cspan style=\"color:#f1fa8c\"\u003eHorácio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eA abordagem mais simples que eu sigo é iniciar criando uma função primária, que no geral chamo de \u003cem\u003emain\u003c/em\u003e e iterar no arquivo CSV usando um \u003ca href=\"https://gist.github.com/lucaspolo/12cba1fad758ec0c541527a0aa4a5fbd\"\u003eDictReader\u003c/a\u003e:\u003c/p\u003e","title":"Lendo arquivos CSV em Python e fazendo requisições - Parte 1"},{"content":"As vezes não nos atentamos aos pequenos detalhes da nosso dia a dia, e após anos programando e lendo código eu esbarrei numa coisa muito interessante: fontes para desenvolvedores.\nEstas fontes específicas para programação ajudam a realçar algumas características específicas do nosso cotidiano, como simbolos e outros detalhes, como também proprorcionam uma leitura agradável do código.\nA que venho usando nos último tempos é a Fira Code, uma fonte criada com uma funcionalide muito interessante, as ligaturas, que são conexões entre simbolos que semanticamente significam uma única coisa. Por exemplo, por mais que \u0026gt;= sejam dois simbolos, o significado é únificado, assim a Fira Code faz o seguinte quando utilizamos ele:\n*Durante a digitação os simbolos vão sendo unidos, na segunda linha vemos isso com o \u0026gt;=*Para instalá-la em sistemas Debian (como o Ubuntu) é muito simples, basta executar sudo apt install fonts-firacode. Depois é apenas necessário alterar a fonte utilizada no editor para a Fira Code e lembrar de habilitar as ligaturas. Lembrando que a fonte cobre diversas linguagens e seus símbolos.\n","permalink":"https://blog.lucaspolo.dev/posts/fira-code-a-fonte-para-programadores/","summary":"\u003cp\u003eAs vezes não nos atentamos aos pequenos detalhes da nosso dia a dia, e após anos programando e lendo código eu esbarrei numa coisa muito interessante: fontes para desenvolvedores.\u003c/p\u003e\n\u003cp\u003eEstas fontes específicas para programação ajudam a realçar algumas características específicas do nosso cotidiano, como simbolos e outros detalhes, como também proprorcionam uma leitura agradável do código.\u003c/p\u003e\n\u003cp\u003eA que venho usando nos último tempos é a \u003ca href=\"https://github.com/tonsky/FiraCode\"\u003eFira Code\u003c/a\u003e, uma fonte criada com uma funcionalide muito interessante, as ligaturas, que são conexões entre simbolos que semanticamente significam uma única coisa. Por exemplo, por mais que \u0026gt;= sejam dois simbolos, o significado é únificado, assim a Fira Code faz o seguinte quando utilizamos ele:\u003c/p\u003e","title":"Fira Code: a fonte para programadores"},{"content":"Alguns anos atrás esbarrei em um vídeo incrível do Nerdologia sobre O poder do Coletivo, que falava como a inteligência das populações poderiam chegar em resultados excelentes para diversas questões (salvo algumas exceções, como polarizações). Todo esse conceito anda lado a lado com o conceito de Big Data e inteligência artifical, onde analisando dados individuais podemos chegar a resultados ótimos pois o erro da multidão tende a se aproximar de zero:\nEsse assunto me chamou muita atenção na época e me motivou a começar a estudar mais matemática, estatística e inteligência artifical. Confesso que não fui muito a fundo nos tópicos, não são coisas tão triviais, porém consegui uma visão boa de tudo que está acontecendo e das possibilidades.\nUm dos tópicos do vídeo é o aprendizado do caminho ótimo que as formigas chegam depois de algumas iterações na busca por alimentos acabam chegando no menor caminho possível entre seu ninho e a fonte de alimento. E não apenas as formigas fazem isso, outros seres vivos também tem um comportamento simila, inclusive os seres humanos.\nE na verdade esse tópico me veio a mente pois recentemente eu esbarrei num projeto muito legal que é um simulador de formigas, criado por Jean Tampton e disponível no Github. Vale muito apena brincar com o software, nele é disparado um grande número de formigas e nós podemos distribuir o alimento, criar paredes e ver como elas se comportam, vale apena brincar com ele:\nAs formigas virtuais aprendenram um caminho até o alimento e otimizaram para a menor rota\n","permalink":"https://blog.lucaspolo.dev/posts/o-poder-do-coletivo-e-o-caminho-das-formigas/","summary":"\u003cp\u003eAlguns anos atrás esbarrei em um vídeo incrível do Nerdologia sobre \u003cstrong\u003eO poder do Coletivo\u003c/strong\u003e, que falava como a inteligência das populações poderiam chegar em resultados excelentes para diversas questões (salvo algumas exceções, como polarizações). Todo esse conceito anda lado a lado com o conceito de Big Data e inteligência artifical, onde analisando dados individuais podemos chegar a resultados ótimos pois o erro da multidão tende a se aproximar de zero:\u003c/p\u003e","title":"O poder do coletivo e o caminho das formigas"},{"content":"Ocasionalmente precisamos instalar o Python na máquina montando (buildando) ele pelo código fonte, seja através de ferramentas como o pyenv ou o asdf como até manualmente. Para isso são necessárias algumas bibliotecas instaladas, segue a lista delas e o comando para instalar em sistemas baseados no Debian:\nsudo apt-get install dpkg-dev \\ build-essential \\ python-dev \\ python3-dev \\ libncursesw5-dev \\ libsqlite3-dev \\ libreadline-dev \\ libbz2-dev \\ libffi-dev \\ libssl-dev \\ libgdbm-dev \\ zlib1g-dev \\ libjpeg-dev \\ libtiff-dev \\ libpq-dev \\ libxml2-dev \\ libxslt1-dev \\ libsdl2-dev \\ libsm-dev \\ libxtst-dev \\ libcurl4-openssl-dev ","permalink":"https://blog.lucaspolo.dev/posts/dependencias-de-montagem-build-do-python/","summary":"\u003cp\u003eOcasionalmente precisamos instalar o Python na máquina montando (buildando) ele pelo código fonte, seja através de ferramentas como o \u003cem\u003epyenv\u003c/em\u003e ou o \u003cem\u003easdf\u003c/em\u003e como até manualmente. Para isso são necessárias algumas bibliotecas instaladas, segue a lista delas e o comando para instalar em sistemas baseados no Debian:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003esudo apt-get install dpkg-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       build-essential \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       python-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       python3-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libncursesw5-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libsqlite3-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libreadline-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libbz2-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libffi-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libssl-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libgdbm-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       zlib1g-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libjpeg-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libtiff-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libpq-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libxml2-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libxslt1-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libsdl2-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libsm-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libxtst-dev \u003cspan style=\"color:#f1fa8c\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                       libcurl4-openssl-dev\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Dependências de montagem (build) do Python"},{"content":"Recentemente eu estava em uma empreitada para aprender um pouco mais sobre desenvolvimento de jogos e comecei a procurar alguns materiais na internet. Hoje em dia boa parte desses materiais são voltados para os grandes frameworks de desenvolvimento de jogos, como o Unit, o que é muito interessante, pois além de facilitarem fazer coisas complexas também já se encaixam com os requisitos do mercado que adotam em massa estes frameworks. Porém eu não estava necessariamente querendo aprender a fazer coisas complexas, mas aprender as bases do desenvolvimento de jogos e tive uma grata surpresa ao descobrir o livro Fundamentos de algoritmos para jogos digitais do David V. Santiago (versão Java).\nO livro, como o próprio nome diz, se foca nos algoritmos fundamentais para desenvolvimentos de jogos, mostrando técnicas básicas para o desenvolvimento de um jogo. A proposta do autor é o desenvolvimento de um jogo de Air Hockey do inicio ao fim, indo desde a criação da tela do jogo e alguns elementos básicos como formas geométricas até um jogo completamente funcional, com desenhos mais complexos, uso de sprites e muito mais.\nPor se tratar de um livro que pode atrair muitos iniciantes em programação o autor teve a real preocupação com este público na hora de tratar os conceitos de programação junto com as particularidades do Java e do framework Swing (que é utilizado para os desenhos gráficos). Todo este cuidado resultou em um livro muito ilustrado e explicações claras para os mais iniciantes, pegando o leitor pela mão para percorrer todos estes tópicos e evitando complexidades que estão fora do escopo do livro. A estrutura do texto é evolutiva, sendo que em cada capítulo se acumula os conhecimentos e desenvolvimento para o próximo capítulo, o que torna muito interessante uma leitura sequêncial em que acompanhamos todas as ideias do autor, porém eu percebi que existem alguns pontos de referência muito interessantes, permitindo que o livro também seja usado para algumas consultas rápidas, principalmente nos algoritmos específicos de jogos, como colisões circulares ou a utilização de sprites.\nJogo pronto, com placar, tela de pause e IA para o adversário!\nA minha experiência de leitura sendo um programador mais experiente também foi muito proveitosa, pois permitiu que eu focasse nos pontos essênciais do desenvolvimentos de jogos e passasse rápido pelos conceitos de programação, além de as vezes me desviar do caminho proposto e fazer algumas refatorações no código que se fossem abordadas no livro poderiam confundir desnecessariamente os mais iniciantes. Ao final da leitura e desenvolvimento eu fiquei muito feliz com o que eu aprendi e senti que este livro também é de muito proveito para programadores mais experientes em áreas que não o desenvolvimento de jogos e agora confesso que estou ansioso por uma sequência com assuntos mais complexos e também versões em outras linguagens.\n","permalink":"https://blog.lucaspolo.dev/posts/resenha-do-livro-fundamentos-de-algoritmos-para-jogos-digitais-de-david-santos/","summary":"\u003cp\u003eRecentemente eu estava em uma empreitada para aprender um pouco mais sobre desenvolvimento de jogos e comecei a procurar alguns materiais na internet. Hoje em dia boa parte desses materiais são voltados para os grandes frameworks de desenvolvimento de jogos, como o Unit, o que é muito interessante, pois além de facilitarem fazer coisas complexas também já se encaixam com os requisitos do mercado que adotam em massa estes frameworks. Porém eu não estava necessariamente querendo aprender a fazer coisas complexas, mas aprender as bases do desenvolvimento de jogos e tive uma grata surpresa ao descobrir o livro \u003ca href=\"https://algol.dev/livros/gds1/\"\u003eFundamentos de algoritmos para jogos digitais do David V. Santiago (versão Java).\u003c/a\u003e\u003c/p\u003e","title":"Resenha do Livro: Fundamentos de Algoritmos para Jogos Digitais de David Santos"},{"content":"Ocasionalmente baixamos diretamente o binário ou até mesmo criamos as nossas aplicações e queremos que elas apareçam na lista de aplicações do Ubuntu com icones e tudo. Para fazer isso é bem simples, basta criar um arquivo no diretório ~/.local/share/applications/, exemplo ~/.local/share/applications/meu_aplicativo.desktop. Depois disso basta preencher o arquivo com o seguinte formato:\n[Desktop Entry] Encoding=UTF-8 Name=Nome da Aplicação Exec=/caminho/para/executavel Icon=/caminho/para/imagem/do/icone Terminal=false Type=Application Categories=Development; Agora já estará disponível o ícone na lista de aplicativos e você poderá invocar o aplicativo pelo launcher.\n","permalink":"https://blog.lucaspolo.dev/posts/criando-entradas-de-desktop-no-ubuntu/","summary":"\u003cp\u003eOcasionalmente baixamos diretamente o binário ou até mesmo criamos as nossas aplicações e queremos que elas apareçam na lista de aplicações do Ubuntu com icones e tudo. Para fazer isso é bem simples, basta criar um arquivo no diretório ~/.local/share/applications/, exemplo ~/.local/share/applications/meu_aplicativo.desktop. Depois disso basta preencher o arquivo com o seguinte formato:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003e[Desktop Entry]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eEncoding\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eUTF-8\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eName\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eNome da Aplicação\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eExec\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/caminho/para/executavel\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eIcon\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e/caminho/para/imagem/do/icone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eTerminal\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eType\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eApplication\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#50fa7b\"\u003eCategories\u003c/span\u003e\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eDevelopment;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAgora já estará disponível o ícone na lista de aplicativos e você poderá invocar o aplicativo pelo launcher.\u003c/p\u003e","title":"Criando entradas de desktop no Ubuntu"},{"content":"No dia a dia utilizo muitas aplicações para auxiliar no meu processo de trabalho, as principais são estas:\nDBeaver Community: este aqui é um destaque, aplicativo que permite acesso a diversos bancos de dados para gerenciamento e execução de queries. Já utilizei ele com PostgreSQL, MySQL, SQLite, MS SQL Server, Oracle e até Informix. Não digo que ele é perfeito, mas como permite a utilização com diversos bancos, é muito prático pois mantém tudo concentrado num único app.\nGhost Writer: editor de texto simples para markdown, que exibe o conteúdo já formatado. O foco é o minimalismo e foco no texto, além de até exibir algumas métricas de produção. Ghost Writer: editor simples de markdown, muito útil para focar no texto apenas.\nFlameshot: ferramenta de captura muito prática e útil, pois permite além de captura toda a tela, a captura de partes. Após a captura é aberta uma janela que permite acrescentar destaques a captura, borrar partes de texto e muitas outras coisas.\nRedis Manager: Aplicativo para gerenciar bancos de dados Redis de maneira gráfica. É bem prático pois permite executar comandos e ver os dados de maneira gráfica.\nRobo 3T: Aplicativo para gerenciar bancos de dados MongoDB, muito prático pois permite importar resultados e também fazer conexões que utilizam ponte SSH.\nKompare: ferramenta gráfica para comparação de arquivos, simples e direta.\nVirtual Box: Aplicativo para virtualização de sistemas operacionais, permitindo rodar diversos S.O\u0026rsquo;s ao mesmo tempo\nX410: Cliente para Xorg (servidor gráfico Linux) no Windows, feito para ser utilizado principalmente com o WSL. A configuração do servidor não é a mais simples, mas depois de pronto toda vez que você iniciar uma aplicação gráfica ele já abrirá a janela.\nCaso você também tenha alguma dica interessante pode mandar nos comentários, adoro testar novas apĺicações, principalmente de software livre. Se quiser ver quais sistemas operacionais, ferramentas de terminal, compiladores, IDEs e editores eu uso confiram estas outras postagems:\nMinhas ferramentas do dia a dia - Sistemas operacionais e terminal. Minhas ferramentas do dia a dia - Compiladores, Interpretadores, IDEs e Editores ","permalink":"https://blog.lucaspolo.dev/posts/minhas-ferramentas-do-dia-a-dia-aplicacoes/","summary":"\u003cp\u003eNo dia a dia utilizo muitas aplicações para auxiliar no meu processo de trabalho, as principais são estas:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca href=\"https://dbeaver.io/\"\u003eDBeaver Community\u003c/a\u003e: este aqui é um destaque, aplicativo que permite acesso a diversos bancos de dados para gerenciamento e execução de queries. Já utilizei ele com PostgreSQL, MySQL, SQLite, MS SQL Server, Oracle e até Informix. Não digo que ele é perfeito, mas como permite a utilização com diversos bancos, é muito prático pois mantém tudo concentrado num único app.\u003c/p\u003e","title":"Minhas ferramentas do dia a dia - Aplicações"},{"content":"Por muito tempo fui adepto de usar os guias de consulta rápida, que eram pequenos livros bem leves e pequenos com um conteúdo resumido e direto sobre algum tópico. Hoje em dia estes livrinhos são apenas história, pois com a internet podemos acessar qualquer manual mais rapidamente e leve (num smartphone, por exemplo). Porém as documentações as vezes são extensas e fica dificil acessar um ponto específico que temos dúvida. Para isso existem os cheat sheets, que são como os guias de consultas rápidas, uma página única, com uma exmplicação concisa e um exemplo sobre o tópico apresentando.\nRecentemente encontrei uma ferramenta muito interessante para sanar aquelas dúvidas rápida que temos as vezes, o cheat.sh. Através de uma simples request com o Curl podemos buscar diversos tópicos, por exemplo: curl cheat.sh/rust/async\nChamando o cheat.sh através do Termux\nAlém de poder acessar via curl, o cheat.sh também tem uma ferramenta de linha de comando que permite que você navegue nos tópicos disponíveis como se navegasse em diretórios, vale apena instalar e utilizar desta forma se você puder:\nUtilizando o cheat.sh através do cliente local, navegando pelos tópicos como diretórios.\n","permalink":"https://blog.lucaspolo.dev/posts/achados-cheat-sheet-facil-e-rapido/","summary":"\u003cp\u003ePor muito tempo fui adepto de usar os guias de consulta rápida, que eram pequenos livros bem leves e pequenos com um conteúdo resumido e direto sobre algum tópico. Hoje em dia estes livrinhos são apenas história, pois com a internet podemos acessar qualquer manual mais rapidamente e leve (num smartphone, por exemplo). Porém as documentações as vezes são extensas e fica dificil acessar um ponto específico que temos dúvida. Para isso existem os cheat sheets, que são como os guias de consultas rápidas, uma página única, com uma exmplicação concisa e um exemplo sobre o tópico apresentando.\u003c/p\u003e","title":"Achados - Cheat Sheet fácil e rápido"},{"content":"Continundo pelas ferramentas que uso no meu dia a dia, agora seguem meus compiladores, interpretadores, IDEs e editores\nCompiladores e Interpretadores Tenho trabalhado com diversas linguagens de programação e destas linguagens também em diversas versões diferentes, por isso ferramentas que me ajudam a gerênciar as linguagens e suas versões são essênciais:\nbuild-essentials: isso aqui não é um software em si, mas um conjunto de diversas ferramentas que ajudam no build de software diversos, principalmente coisas desenvolvidas em C e C++. É algo que não vem por padrão em uma instalação GNU/Linux, mas a partir do momento que você precisa compilar uma aplicação isso será exigido. asdf-vm: O asdf-vm surge como uma ferramenta universal para o gerenciamento de versões de intepretadores, compiladores e outras ferramentas. Sua utilização é bem simples, hoje utilizo ela principalmente para Python, NodeJS e Go. Aqui um artigo em português sobre a instalação dele. rustup: A ferramenta criada para gerênciar versões da suíte da linguagem Rust é uma mão na roda, além de facilitar a instalação e gerênciar versões, também permite controlar os alvos de compilação (seus toolchains, exemplo: Linux, Windows, ARM, etc). OpenJDK: A implementação de referência do Java tem sido a minha preferida nos ambientes de desenvolvimento e execução faz um tempo. Lembro de antigamente ela ter uma performance inferior, porém cada vez mais a comunidade se uniu em torno dela para aprimora-la. IDEs e Editores Visual Studio Code: o editor de texto criado pela Microsoft tem se destacado muito nos últimos anos, principalmente pela facilidade que oferece para a utilização de plugins que o tornam uma ferramenta muito poderosa. Tenho utilizado ele principalmente para o desenvolvimento Python, Rust, NodeJS e Go, com os seguintes plugins: Python: extensão para programar e debugar em Python. rust-analyzer: extensão que faz o linter, autocomplete e análise estática do código Rust. CodeLLDB: extensão que permite debugar códigos gerados pela LLVM, utilizo para debugara projetos Rust, mas funciona para outras ferramentas que utilizam LLVM. crates: extensão para exibir quais dependências estão atualizadas e desatualizadas. Go: extensão para análise e debugger de código Go. PyCharm Community e a suíte da JetBrains: A IDE da Jetbrains dedicada ao Python oferece muitos recursos interessante, desde o linter até o debugger integrado. Por ser um pouco mais pesado eu só utilizado nos projetos grandes com muitos arquivos, pois ele facilita muito a busca e análise no projeto. Uso principalmente o PyCharm, mas também gosto de usar as outras ferramentas disponíveis da JetBrains para projetos maiores, como a IntelliJ e Webstorm. Micro Editor: Esse cara eu descobri recentemente e tem sido muito útil, como o próprio nome indica ele é um editor de terminal maior que o Nano mas bem mais simples que o Vim pois permite utilizar atalhos do dia a dia como Ctrl+S para salvar, Ctrl+C/Ctrl+V para copiar e colar. Utilizo muito para a edição de scripts mais simples em Bash e Python. Micro Editor: um editor simples que roda direto no terminal e faz até análise estática quando junto com o Flake8 (no caso de Python)\nVisual Studio: tenho utilizado o irmão mais velho do VSCode para o desenvolvimento de aplicações com .Net Core e C#, ela é uma IDE completa em todos os sentidos, porém tem o custo de ser a mais pesada aqui da lista. Além de C#, ela também ajuda no desenvolvimento de muitas outras linguagens e ferramentas. Vale uma grande menção honrosa ao Vim, o editor onipresente nas distribuições Linux, que através de plugins pode ser praticamente convertido numa IDE. No meu dia a dia o uso é básico porém tenho colegas que o usam como editor principal. ","permalink":"https://blog.lucaspolo.dev/posts/minhas-ferramentas-do-dia-a-dia-compiladores-interpretadores-ides-e-editores/","summary":"\u003cp\u003eContinundo pelas ferramentas que uso no meu dia a dia, agora seguem meus compiladores, interpretadores, IDEs e editores\u003c/p\u003e\n\u003ch2 id=\"compiladores-e-interpretadores\"\u003eCompiladores e Interpretadores\u003c/h2\u003e\n\u003cp\u003eTenho trabalhado com diversas linguagens de programação e destas linguagens também em diversas versões diferentes, por isso ferramentas que me ajudam a gerênciar as linguagens e suas versões são essênciais:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://linuxhint.com/install-build-essential-ubuntu/#:~:text=The%20build%2Dessentials%20packages%20are,required%20to%20compile%20a%20program.\"\u003ebuild-essentials\u003c/a\u003e: isso aqui não é um software em si, mas um conjunto de diversas ferramentas que ajudam no build de software diversos, principalmente coisas desenvolvidas em C e C++. É algo que não vem por padrão em uma instalação GNU/Linux, mas a partir do momento que você precisa compilar uma aplicação isso será exigido.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/asdf-vm/asdf\"\u003easdf-vm\u003c/a\u003e: O asdf-vm surge como uma ferramenta universal para o gerenciamento de versões de intepretadores, compiladores e outras ferramentas. Sua utilização é bem simples, hoje utilizo ela principalmente para Python, NodeJS e Go. \u003ca href=\"https://www.programandocomcarlos.com.br/2020/01/asdf-gerenciador-de-versao-extensivel.html\"\u003eAqui um artigo em português sobre a instalação dele\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.google.com/search?q=rustup\u0026amp;oq=rustup\u0026amp;aqs=chrome.0.69i59j0l9.962j0j7\u0026amp;sourceid=chrome\u0026amp;ie=UTF-8\"\u003erustup\u003c/a\u003e: A ferramenta criada para gerênciar versões da suíte da linguagem Rust é uma mão na roda, além de facilitar a instalação e gerênciar versões, também permite controlar os alvos de compilação (seus toolchains, exemplo: Linux, Windows, ARM, etc).\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://openjdk.java.net/\"\u003eOpenJDK\u003c/a\u003e: A implementação de referência do Java tem sido a minha preferida nos ambientes de desenvolvimento e execução faz um tempo. Lembro de antigamente ela ter uma performance inferior, porém cada vez mais a comunidade se uniu em torno dela para aprimora-la.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"ides-e-editores\"\u003eIDEs e Editores\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://code.visualstudio.com/\"\u003eVisual Studio Code\u003c/a\u003e: o editor de texto criado pela Microsoft tem se destacado muito nos últimos anos, principalmente pela facilidade que oferece para a utilização de plugins que o tornam uma ferramenta muito poderosa. Tenho utilizado ele principalmente para o desenvolvimento Python, Rust, NodeJS e Go, com os seguintes plugins:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://marketplace.visualstudio.com/items?itemName=ms-python.python\"\u003ePython\u003c/a\u003e: extensão para programar e debugar em Python.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer\"\u003erust-analyzer\u003c/a\u003e: extensão que faz o linter, autocomplete e análise estática do código Rust.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb\"\u003eCodeLLDB\u003c/a\u003e: extensão que permite debugar códigos gerados pela LLVM, utilizo para debugara projetos Rust, mas funciona para outras ferramentas que utilizam LLVM.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://marketplace.visualstudio.com/items?itemName=serayuzgur.crates\"\u003ecrates\u003c/a\u003e: extensão para exibir quais dependências estão atualizadas e desatualizadas.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://code.visualstudio.com/docs/languages/go\"\u003eGo\u003c/a\u003e: extensão para análise e debugger de código Go.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.jetbrains.com/pycharm/download/\"\u003ePyCharm Community\u003c/a\u003e e a suíte da JetBrains: A IDE da Jetbrains dedicada ao Python oferece muitos recursos interessante, desde o linter até o debugger integrado. Por ser um pouco mais pesado eu só utilizado nos projetos grandes com muitos arquivos, pois ele facilita muito a busca e análise no projeto. Uso principalmente o PyCharm, mas também gosto de usar as outras ferramentas disponíveis da JetBrains para projetos maiores, como a IntelliJ e Webstorm.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://micro-editor.github.io/\"\u003eMicro Editor\u003c/a\u003e: Esse cara eu descobri recentemente e tem sido muito útil, como o próprio nome indica ele é um editor de terminal maior que o Nano mas bem mais simples que o Vim pois permite utilizar atalhos do dia a dia como Ctrl+S para salvar, Ctrl+C/Ctrl+V para copiar e colar. Utilizo muito para a edição de scripts mais simples em Bash e Python.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg alt=\"Micro Editor no terminal editando um script Python, com o aviso undefined name \u0026lsquo;send\u0026rsquo; do Flake8 na barra inferior\" loading=\"lazy\" src=\"/images/posts/minhas-ferramentas-do-dia-a-dia-compiladores-interpretadores-ides-e-editores/Screenshot_from_2021-05-25_11-23-41.png\"\u003e\n\u003cem\u003eMicro Editor: um editor simples que roda direto no terminal e faz até análise estática quando junto com o Flake8 (no caso de Python)\u003c/em\u003e\u003c/p\u003e","title":"Minhas ferramentas do dia a dia - Compiladores, Interpretadores, IDEs e Editores"},{"content":"Gosto muito da praticidade dos cheat sheets, que são pequenas páginas, que podem ser impressas ou não, que contém um resumo sobre algum assunto específico. Desta vez quero compartilhar uma que descobri recentemente sobre a linguagem Rust, que venho aprendendo nos últimos tempos. Clique na imagem para acessar!\n","permalink":"https://blog.lucaspolo.dev/posts/achados-rust-cheat-sheet/","summary":"\u003cp\u003eGosto muito da praticidade dos cheat sheets, que são pequenas páginas, que podem ser impressas ou não, que contém um resumo sobre algum assunto específico. Desta vez quero compartilhar uma que descobri recentemente sobre a linguagem Rust, que venho aprendendo nos últimos tempos. Clique na imagem para acessar!\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://cheats.rs/\"\u003e\u003cimg alt=\"Página do Rust Language Cheat Sheet com o índice de seções: construções da linguagem, biblioteca padrão, ferramentas e guias\" loading=\"lazy\" src=\"/images/posts/achados-rust-cheat-sheet/image.png\"\u003e\u003c/a\u003e\u003c/p\u003e","title":"Achados - Rust Cheat Sheet"},{"content":"Durante a minha jornada venho acumulando algumas ferramentas para ajudar no meu dia a dia no desenvolvimento de software, na maior parte são coisas simples mas que fazem muita diferença na produtividade.\nNesta primeira parte irei abordar os sistemas operacionais que uso e os aplicativos de terminal.\nSistemas Operacionais Ubuntu GNU/Linux: O Ubuntu tem sido meu sistema operacional há mais de dez anos. Quando desenvolvemos para a web, sistemas tipo Unix são preferênciais devido as ferramentas que eles já oferecem por padrão, além de serem na maioria dos casos os ambientes de deploy das aplicações. Além de toda a \u0026ldquo;tralha\u0026rdquo; de desenvolvimento, o GNU/Linux tem cada vez mais ferramentas para o uso comum, como editores e jogos. Eu gosto de usar o Ubuntu pois já sou acostumado com sua interface, mas acredito que a indicação aqui seja principalmente utilizar uma distribuição que você goste e se adapte. Windows 10: O Windows tem sido uma grata surpresa para mim, além de utiliza-lo para as aplicações que só rodam no Windows, junto com o WSL2 tenho conseguido utilizar qualquer ferramenta GNU/Linux nele, inclusive aplicações gráficas graças ao X410. Terminal A primeira coisa que vale citar é o emulador de terminal que utilizo, o Tilix. Ele possui algumas ferramentas bem interessantes como split de janelas, abas e é bem leve. Além disso ele possui o modo Quake, que é um modo onde o terminal aparece no topo da tela (ou onde você configurar) de maneira rápida de mais prática.\nTilix: rodando três sessões ao mesmo tempo, Zenith, bat e Dust respectivamente.\nNo Windows estou utilizando o Windows Terminal, que se conecta automaticamente no WSL2 e tem ótimas funções similares ao Tilix, como split de terminal e abas.\nAlém dos emuladores de terminal, há também todo o conjunto de aplicativos que utilizo pelo terminal para me ajudar no meu trabalho diário:\ntldr: Too Long, Don\u0026rsquo;t Read. Esta ferramenta surge como uma alternativa mais rápida (porém não substitui) os manuais do Linux. O que ele faz é exibir como utilizar os comandos nas suas maneiras mais utilizadas, o que facilita quando precisamos lembrar, por exemplo, como extrair aquele arquivo tar.gz. Bash Git Prompt: aplicação que enriquece o bash com informações do Git caso esteja em um repositório. htop: algumas vezes precisamos monitorar os processos do sistema, por padrão o GNU/Linux vem com o top, que exibe os processos e seu consumo de memória e processamento. Apesar de precisa, a exibição do top não é a mais amigável, ai entra o htop, uma ferramenta que faz a mesma coisa de maneira mais amigável, permitindo ordenar processos por diversas métricas, fazer buscas e mandar sinais para os processos. Docker: a ferramenta onipresente e que mudou o mundo, utilizo ele diariamente para gerenciar aplicativos que preciso instalar porém quero mante-los isolados. Todo o conceito de conteinerização é algo muito interessante e poderoso. Além do Docker existem outras alternativas como o Podman. ctop: O ctop é um aplicativo amarrado diretamente ao Docker. Ele permite gerenciar os containers, verificar a utilização de memória, acessar logs e outras coisas. Apesar dos comandos do Docker não serem complicados demais, o ctop agiliza muito lidar com vários containers. ctop: permite gerenciar facilmente os containers que estão disponíveis\nredis-cli: O redis-cli é uma ferramenta de terminal que permite se conectar e enviar comandos para servidores Redis. Suporta autocomplete de diversos comandos e também a execução de scripts. Zenith: Aplicação gráfica que permite ver diversas métricas do computador. Faz um pouco do trabalho do htop, porém também exibe gráficos como podemos ver na captura de tela acima. bat: Similar ao cat, porém faz syntax highlight de códigos fontes, facilitando a leitura. Delta: Aplicativo que diff muito útil para o terminal, faz syntax highlight e pode ser configurado para substituir o diff padrão do Git. Dust: Similar o aplicativo du (Disk Usage), exibe de maneira mais amigável o tamanho dos diretório e arquivos no terminal. Estas são as aplicações que mais uso, porém existem algumas outras que não lembrei no momento e posso ir atualizando este post de tempos em tempos. Se você conhece alguma ferramenta interessante, útil ou divertida para o terminal coloca ela nos comentários que vou adorar testá-la.\n","permalink":"https://blog.lucaspolo.dev/posts/minhas-ferramentas-do-dia-a-dia-sistemas-operacionais-e-terminal/","summary":"\u003cp\u003eDurante a minha jornada venho acumulando algumas ferramentas para ajudar no meu dia a dia no desenvolvimento de software, na maior parte são coisas simples mas que fazem muita diferença na produtividade.\u003c/p\u003e\n\u003cp\u003eNesta primeira parte irei abordar os sistemas operacionais que uso e os aplicativos de terminal.\u003c/p\u003e\n\u003ch2 id=\"sistemas-operacionais\"\u003eSistemas Operacionais\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://ubuntu.com/\"\u003eUbuntu GNU/Linux\u003c/a\u003e: O Ubuntu tem sido meu sistema operacional há mais de dez anos. Quando desenvolvemos para a web, sistemas tipo Unix são preferênciais devido as ferramentas que eles já oferecem por padrão, além de serem na maioria dos casos os ambientes de deploy das aplicações. Além de toda a \u0026ldquo;tralha\u0026rdquo; de desenvolvimento, o GNU/Linux tem cada vez mais ferramentas para o uso comum, como editores e jogos. Eu gosto de usar o Ubuntu pois já sou acostumado com sua interface, mas acredito que a indicação aqui seja principalmente utilizar uma distribuição que você goste e se adapte.\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.microsoft.com/pt-br/windows/get-windows-10\"\u003eWindows 10\u003c/a\u003e: O Windows tem sido uma grata surpresa para mim, além de utiliza-lo para as aplicações que só rodam no Windows, junto com o WSL2 tenho conseguido utilizar qualquer ferramenta GNU/Linux nele, inclusive aplicações gráficas graças ao X410.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"terminal\"\u003eTerminal\u003c/h2\u003e\n\u003cp\u003eA primeira coisa que vale citar é o emulador de terminal que utilizo, o \u003ca href=\"https://gnunn1.github.io/tilix-web/\"\u003eTilix\u003c/a\u003e. Ele possui algumas ferramentas bem interessantes como split de janelas, abas e é bem leve. Além disso ele possui o modo Quake, que é um modo onde o terminal aparece no topo da tela (ou onde você configurar) de maneira rápida de mais prática.\u003c/p\u003e","title":"Minhas ferramentas do dia a dia - Sistemas operacionais e Terminal"},{"content":"Sempre estamos aprendendo, pelo menos todo dia podemos tirar uma lição do que aconteceu. Algumas coisas são mais marcantes que outras, inclusive podem e devem ser repassadas para outros, podendo ajudar pessoas que estão iniciando ou até as mais experientes.\nPara documentar as coisas de maneira mais direta criei uma pequena página onde documento meus aprendizados, principalmente devido a erros que cometi. O link para ler essa página é http://aprendizado.lucaspolo.dev\n","permalink":"https://blog.lucaspolo.dev/posts/meus-pequenos-aprendizados-diarios/","summary":"\u003cp\u003eSempre estamos aprendendo, pelo menos todo dia podemos tirar uma lição do que aconteceu. Algumas coisas são mais marcantes que outras, inclusive podem e devem ser repassadas para outros, podendo ajudar pessoas que estão iniciando ou até as mais experientes.\u003c/p\u003e\n\u003cp\u003ePara documentar as coisas de maneira mais direta criei uma pequena página onde documento meus aprendizados, principalmente devido a erros que cometi. O link para ler essa página é \u003ca href=\"http://aprendizado.lucaspolo.dev\"\u003ehttp://aprendizado.lucaspolo.dev\u003c/a\u003e\u003c/p\u003e","title":"Meus pequenos aprendizados diários"},{"content":"A história da computação é algo muitas vezes cíclico, onde conceitos com quase 50 anos retornam, às vezes na mesma forma, as vezes em uma nova roupagem. Vamos dar um zoom num dos conceitos mais comuns da programação moderna, a programação orientada a objetos.\nA primeira coisa que eu gostaria de falar é que programamos orientado a classes mas os sistemas não rodam orientado a objetos.\nO QUE?\nO que fazemos na verdade é estruturação de códigos em classe, o que não é ruim mas no decorrer dos próximos parágrafos vou tentar explicar melhor. Isso inclusive constata a diferença entre como organizamos nosso código e como isso pode ser diferente da organização das estruturas do nosso código em execução.\nClasses no código, procedimentos na execução Se você, que nem eu, começou a programar nos últimos 20 ou até 30 anos com certeza lidou com a programação orientada a objetos, provavelmente com linguagens como C++, Java, C#, Python, Ruby ou qualquer outra linguagem que dê suporte a classes ou até protótipos (no caso de Javascript). Estas linguagens estruturam fortemente o código utilizando classes e a partir dela instanciam estes obetos, porém o ciclo de vida dos objetos tende a ser muito curto e contido no escopo de outros métodos, o que tem benefícios se tratando de concorrência (os objetos vivem tão pouco e num escopo tão restrito que não compartilham nenhum estado), gestão de memória (como os objetos são menores e vivem num escopo restrito, fica fácil controlar seu início e fim) e também manutenção de código, pois a execução do código ainda fica linear em sua execução. Porém é necessário deixar claro que isso não é algo que foi decidido da noite para o dia, durante muito tempo essa abordagem não foi a prioritária para o desenvolvimento Java, que durante muito tempo estruturou de forma diferente suas aplicações com EJBs no framework Java Enterprise Edition (Java EE).\nEsta estrutura de código funciona muito bem, porém como já fazemos uma separação mais clara entre procedimentos (ou funções) e estruturas de dados, poderíamos potencializar os benefícios acima espelhando a maneira como nosso programa executa com a maneira que estruturamos nosso código, isso abriu um grande espaço para linguagens funcionais que já lidam bem com programação concorrente, gerenciamento de memória e manutenabilidade, e assim vemos o crescimento de linguagens como Clojure, Elm, F# e até Haskell.\nDiferenças entre OOP e FP Fonte: https://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html\nSmalltalk e a troca de mensagens Você pode pensar no motivo de já não termos adotado linguagens funcionais logo de cara, já que a programação orientada a objetos na maneira como fazemos hoje tem uma impedância entre a estrutura de código e a estrutura interna do programa em si, mas como falei acima, isso nem sempre foi assim. No decorrer dos anos 70 uma linguagem muito famosa surgiu, o Smalltalk, sendo uma linguagem orientada a objetos, um dos seus maiores diferenciais era a maneira como ela gerenciava seus objetos. Ao iniciar um programa os objetos eram carregados por sua máquina virtual e começavam a trocar mensagens entre eles, o ciclo de vida desses objetos era mais longo e permitia inclusive tirar uma fotografia do momento atual da máquina virtual e carregá-la novamente no mesmo estado posteriormente.\nDiagra de sequência com mensagens UML Fonte: https://en.wikipedia.org/wiki/Sequence_diagram\nProgramadores experientes em Smalltalk e posteriormente em Java inclusive criaram uma forma de documentar toda essa estrutura em uma linguagem bem conhecida, o Unified Model Language, porém como vamos descobrir abaixo, este modelo de execução sofria de alguns problemas e o UML acabou ficando subutilizado, pelo fato de só utilizarmos classes e não orientação a objetos de uma maneira purista, ou já utilizarmos logo uma linguagem funcional.\nEnterprise Java Beans O modelo se modernizou para o século 21 quando foi adotado pelo Java Enterprise Edition no seu começo, onde estes objetos que ficavam carregados em memória, na forma de pools, eram chamados de Enterprise Java Beans e permitiam coisas como a distribuição entre diversos servidores (um EJB de uma máquina poderiam passar uma mensagens, em forma de invocação de método, para um EJB em outra máquina).\nO modelo orientado a objetos, apesar de muito robusto, era complexo e exigia configurações de máquina bem exigentes (trabalhei em lugares que tinham oito servidores de 32 núcleos e 64 GB de RAM para executar uma única aplicação Java) e isto começou a fazer a estrutura ficar cada vez menos interessante, mesmo o ciclo de vida dos objetos tendo um função de passiva-los (ou seja, eles eram serializados e salvos em um lugar mais econômico da JVM), sendo que depois perceberam que era melhor criar EJBs sem estado (ou seja, a primeira execução do EJB não mantinha nada armazenado que pudesse afetar sua segunda execução) e logo a máquina virtual do Java, por decisões arquiteturais e para facilitar a vida do coletor de lixo (responsável por liberar memória) começou a favorecer objetos que fossem instanciados rapidamente e morriam mais rapidamente ainda, permitindo a execução em máquinas com muito menos memória, favorecido pelo crescimento de frameworks mais simples de desenvolver como o Spring.\nCiclo de vida de um EJB Fonte: https://examples.javacodegeeks.com/enterprise-java/ejb3/ejb-life-cycle-example/\nE hoje? Hoje em dia, os modelos mais comuns de orientação a objetos favorecem criar o código em forma de classes porém a execução de ocorre muito mais proceduralmente. Isso ajuda no gerenciamento de memória e tira da frente alguns problemas em relação a paralelismo de código, pois quando você tem vários objetos rodando em paralelo é necessário decidir qual é a prioridade e tempo de máquina que cada método de cada objeto deve ter e isto foi uma decisão que os desenvolvedores de linguagens e máquinas virtuais decidiram não priorizar.\nEsta é a primeira parte do post e explica um pouco da história da programação orientada a objetos e sua evolução, porém como falei acima, as coisas ocorrem de maneira cíclica e o modelo criado pelo Smalltalk seria retomado mais recentemente de outra forma, que será explicada num próximo post.\n","permalink":"https://blog.lucaspolo.dev/posts/programacao-orientada-a-ob-classes/","summary":"\u003cp\u003eA história da computação é algo muitas vezes cíclico, onde conceitos com quase 50 anos retornam, às vezes na mesma forma, as vezes em uma nova roupagem. Vamos dar um zoom num dos conceitos mais comuns da programação moderna, a programação orientada a objetos.\u003c/p\u003e\n\u003cp\u003eA primeira coisa que eu gostaria de falar \u003cstrong\u003eé que programamos orientado a classes mas os sistemas não rodam orientado a objetos.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Cão-da-pradaria de costas virando dramáticamente e encarando a câmera.\" loading=\"lazy\" src=\"/images/posts/programacao-orientada-a-ob-classes/beaver.gif\"\u003e\n\u003cem\u003eO QUE?\u003c/em\u003e\u003c/p\u003e","title":"Programação Orientada a ob... classes"},{"content":"import asyncio from random import randint import time async def funcao_assincrona_com_possivel_chamada_sincrona(n: int): # A corrotina é uma função educadinha, que quando vai fazer # algo que pode demorar fala assim: # \u0026#34;Cara, isso aqui vai demorar pois é operação de IO, podem ir fazendo outra coisa\u0026#34; # Assin o interpretador é liberado para executar outras instruções. for i in range(10): print(f\u0026#39;Task {n} - {i}\u0026#39;) # Neste ponto (await) a corrotina concede o direito de execução # de volta, ai é permitido rodar outras corrotinas # que estiverem aguardando, é aqui que a rotina fala # \u0026#34;Gente, pode continuar ai que vou demorar aqui um pouco\u0026#34; # Aqui poderia ser uma requisição web demorada, # um acesso a bancos de dados e outras coisas, por exemplo. print(f\u0026#39;Liberando task {n} - {i}\u0026#39;) await asyncio.sleep(randint(0,3)) print(f\u0026#39;Retomando task {n} - {i}\u0026#39;) # Aqui acontece a quebra, existe a chance (1 em 1000) de # ser executado um processo blocante que irá # blocar todos as tarefas que estão rodando concorrentemente # Ela não é tão educada quanto parecia quando entra aqui. sorte = randint(0, 1000) if sorte == 50: print print(f\u0026#39;Task {n} blocou a GIL no passo {i}, que azar\u0026#39;) time.sleep(3) # Isso aqui blocante! print(f\u0026#39;Concluindo task {n} - {i}\u0026#39;) async def main(): # Irá criar mil tarefinhas que serão disparadas em \u0026#34;paralelo\u0026#34; (na verdade concorrentemente) tasks_assincronas_que_podem_blocar = { asyncio.create_task( funcao_assincrona_com_coisa_assincrona(i) ) for i in range(10000) } # Executa todas elas, aguardando todas serem concluidas await asyncio.wait( tasks_assincronas_que_podem_blocar, return_when=asyncio.ALL_COMPLETED ) if __name__ == \u0026#34;__main__\u0026#34;: asyncio.run(main()) ","permalink":"https://blog.lucaspolo.dev/posts/micro-tutorial-de-como-funcionam-corrotinas/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e asyncio\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e random \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e randint\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e time\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003easync\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003efuncao_assincrona_com_possivel_chamada_sincrona\u003c/span\u003e(n: \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eint\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# A corrotina é uma função educadinha, que quando vai fazer\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# algo que pode demorar fala assim:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# \u0026#34;Cara, isso aqui vai demorar pois é operação de IO, podem ir fazendo outra coisa\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Assin o interpretador é liberado para executar outras instruções.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#ff79c6\"\u003ein\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003erange\u003c/span\u003e(\u003cspan style=\"color:#bd93f9\"\u003e10\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Task \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003en\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# Neste ponto (await) a corrotina concede o direito de execução\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# de volta, ai é permitido rodar outras corrotinas\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# que estiverem aguardando, é aqui que a rotina fala\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# \u0026#34;Gente, pode continuar ai que vou demorar aqui um pouco\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# Aqui poderia ser uma requisição web demorada,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# um acesso a bancos de dados e outras coisas, por exemplo.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Liberando task \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003en\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eawait\u003c/span\u003e asyncio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esleep(randint(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e)) \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Retomando task \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003en\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# Aqui acontece a quebra, existe a chance (1 em 1000) de \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# ser executado um processo blocante que irá \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# blocar todos as tarefas que estão rodando concorrentemente\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#6272a4\"\u003e# Ela não é tão educada quanto parecia quando entra aqui.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sorte \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e randint(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e1000\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e sorte \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e50\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Task \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003en\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e blocou a GIL no passo \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e, que azar\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            time\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003esleep(\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e)  \u003cspan style=\"color:#6272a4\"\u003e# Isso aqui  blocante!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Concluindo task \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003en\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e - \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003ei\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003easync\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003emain\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Irá criar mil tarefinhas que serão disparadas em \u0026#34;paralelo\u0026#34; (na verdade concorrentemente)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    tasks_assincronas_que_podem_blocar \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        asyncio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ecreate_task(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            funcao_assincrona_com_coisa_assincrona(i)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#ff79c6\"\u003ein\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003erange\u003c/span\u003e(\u003cspan style=\"color:#bd93f9\"\u003e10000\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Executa todas elas, aguardando todas serem concluidas\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eawait\u003c/span\u003e asyncio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ewait(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        tasks_assincronas_que_podem_blocar,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        return_when\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003easyncio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eALL_COMPLETED\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e__name__\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    asyncio\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003erun(main())\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Micro tutorial de como funcionam corrotinas"},{"content":"Fazer um jogo de JoKemPo em Python é simples, mas para complementar fiz alguns tratamentos diferentes, como a captura de KeyboardException para tratar a saída do programa.\nfrom random import choice # Esta função serve para escolher aleatoriamente um elemento da lista! # Dicionário de movimentos, na chave a opção e no valor quem ela ganha! MOVES = { \u0026#39;rock\u0026#39;: \u0026#39;scissors\u0026#39;, \u0026#39;paper\u0026#39;: \u0026#39;rock\u0026#39;, \u0026#39;scissors\u0026#39;: \u0026#39;paper\u0026#39;, } # Lista de opções OPTIONS = list(MOVES.keys()) def _get_user_choice(): \u0026#34;\u0026#34;\u0026#34; Recupera e valida a opção do usuário \u0026#34;\u0026#34;\u0026#34; while True: user_choice = input(\u0026#39;Choose one option [rock/paper/scissors] - ctrl+c to exit: \u0026#39;) if user_choice not in OPTIONS: print(\u0026#39;Choose a valid option!\u0026#39;) continue return user_choice def _jokenpo(user_choice, computer_choice): \u0026#34;\u0026#34;\u0026#34; Valida a regra do jogo, comparando a escolha do usuário com a do computador! \u0026#34;\u0026#34;\u0026#34; if MOVES[user_choice] == computer_choice: print(\u0026#39;You win!\u0026#39;) elif MOVES[computer_choice] == user_choice: print(\u0026#39;I win!\u0026#39;) else: print(\u0026#39;Meh!\u0026#39;) if __name__ == \u0026#34;__main__\u0026#34;: while True: # Roda infinitamente try: user_choice = _get_user_choice() except KeyboardInterrupt: print(\u0026#39;\\nBye!\u0026#39;) # Caso o usuário aperte ctrl+c sairá do loop infinito break computer_choice = choice(OPTIONS) # Escolhe a opção do computador _jokenpo( user_choice=user_choice, computer_choice=computer_choice, ) ","permalink":"https://blog.lucaspolo.dev/posts/jokenpo-em-python/","summary":"\u003cp\u003eFazer um jogo de JoKemPo em Python é simples, mas para complementar fiz alguns tratamentos diferentes, como a captura de \u003cstrong\u003eKeyboardException\u003c/strong\u003e para tratar a saída do programa.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e random \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e choice  \u003cspan style=\"color:#6272a4\"\u003e# Esta função serve para escolher aleatoriamente um elemento da lista!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# Dicionário de movimentos, na chave a opção e no valor quem ela ganha!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eMOVES \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;rock\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;scissors\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;paper\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;rock\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;scissors\u0026#39;\u003c/span\u003e: \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;paper\u0026#39;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e# Lista de opções\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eOPTIONS \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elist\u003c/span\u003e(MOVES\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ekeys())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003e_get_user_choice\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    Recupera e valida a opção do usuário\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ewhile\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eTrue\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        user_choice \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003einput\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Choose one option [rock/paper/scissors] - ctrl+c to exit: \u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e user_choice \u003cspan style=\"color:#ff79c6\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003ein\u003c/span\u003e OPTIONS:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Choose a valid option!\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003econtinue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e user_choice\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003e_jokenpo\u003c/span\u003e(user_choice, computer_choice):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    Valida a regra do jogo, comparando a escolha do usuário com a do computador!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e MOVES[user_choice] \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e computer_choice:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;You win!\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eelif\u003c/span\u003e MOVES[computer_choice] \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e user_choice:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;I win!\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Meh!\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e__name__\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ewhile\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003eTrue\u003c/span\u003e:  \u003cspan style=\"color:#6272a4\"\u003e# Roda infinitamente\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            user_choice \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e _get_user_choice()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003eexcept\u003c/span\u003e KeyboardInterrupt:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003eBye!\u0026#39;\u003c/span\u003e)  \u003cspan style=\"color:#6272a4\"\u003e# Caso o usuário aperte ctrl+c sairá do loop infinito\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ff79c6\"\u003ebreak\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        computer_choice \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e choice(OPTIONS)  \u003cspan style=\"color:#6272a4\"\u003e# Escolhe a opção do computador\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        _jokenpo(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            user_choice\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003euser_choice,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            computer_choice\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003ecomputer_choice,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"JoKenPo em Python"},{"content":"Disclaimer: Nunca faça isso na real!\nPython tem uma natureza funcional muito boa (não tão boa quanto linguagens funcionais, é claro), o que de certo modo faz ele similar com Javascript, utilizando closures e afins. Inclusive permite construções similares a esta abaixo:\ndef Pessoa(nome: str, sobrenome:str, idade:int): def getNome(): return nome def getSobrenome(): return sobrenome def getNomeCompleto(): return f\u0026#39;{nome} {sobrenome}\u0026#39; def getIdade(): return idade return { \u0026#39;getNome\u0026#39;: getNome, \u0026#39;getSobrenome\u0026#39;: getSobrenome, \u0026#39;getNomeCompleto\u0026#39;: getNomeCompleto, \u0026#39;getIdade\u0026#39;: getIdade, } p = Pessoa(\u0026#39;Jar Jar\u0026#39;, \u0026#39;Binks\u0026#39;, 38) print(p[\u0026#39;getNomeCompleto\u0026#39;](), p[\u0026#39;getIdade\u0026#39;]()) Python não define um meio de criar objetos dinâmicos como Javascript, devido a sua forte tipagem, por isso usei a estrutura de dicionário. O que acontece na verdade é que devolvemos uma coleção de funções que acessam os atributos do \u0026ldquo;construtor\u0026rdquo; através de closures.\nDesde o ES6/ES2015 temos como declarar classes em Javascript utilizando keywords como class, constructor, etc, o que deixa bem mais limpo e agrupado, mas tudo isso ainda é syntax suggar para a estrutura de criação de objetos que existia anteriormente.\nUpdate: Consegui usar as chamadas de método normalmente, porém tive que definir uma classe apenas de quebra galho (a classe Object) apenas para poder usar setattr e para isto é necessário a classe definir __dict__:\ndef Pessoa(nome: str, sobrenome:str, idade:int): class Object: pass def getNome(): return nome def getSobrenome(): return sobrenome def getNomeCompleto(): return f\u0026#39;{nome} {sobrenome}\u0026#39; def getIdade(): return idade o = Object() setattr(o, \u0026#39;getNome\u0026#39;, getNome) setattr(o, \u0026#39;getSobrenome\u0026#39;, getSobrenome) setattr(o, \u0026#39;getNomeCompleto\u0026#39;, getNomeCompleto) setattr(o, \u0026#39;getIdade\u0026#39;, getIdade) return o p = Pessoa(\u0026#39;Jar Jar\u0026#39;, \u0026#39;Binks\u0026#39;, 38) print(f\u0026#39;{p.getNomeCompleto()} - {p.getIdade()}\u0026#39;) ","permalink":"https://blog.lucaspolo.dev/posts/python-que-nem-javascript/","summary":"\u003cp\u003eDisclaimer: Nunca faça isso na real!\u003c/p\u003e\n\u003cp\u003ePython tem uma natureza funcional muito boa (não tão boa quanto linguagens funcionais, é claro), o que de certo modo faz ele similar com Javascript, utilizando closures e afins. Inclusive permite construções similares a esta abaixo:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003ePessoa\u003c/span\u003e(nome: \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e, sobrenome:\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e, idade:\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eint\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003egetNome\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e nome\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003egetSobrenome\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e sobrenome\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003egetNomeCompleto\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003enome\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003esobrenome\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003egetIdade\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e idade\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;getNome\u0026#39;\u003c/span\u003e: getNome,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;getSobrenome\u0026#39;\u003c/span\u003e: getSobrenome,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;getNomeCompleto\u0026#39;\u003c/span\u003e: getNomeCompleto,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;getIdade\u0026#39;\u003c/span\u003e: getIdade,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ep \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e Pessoa(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Jar Jar\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;Binks\u0026#39;\u003c/span\u003e, \u003cspan style=\"color:#bd93f9\"\u003e38\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(p[\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;getNomeCompleto\u0026#39;\u003c/span\u003e](), p[\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;getIdade\u0026#39;\u003c/span\u003e]())\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePython não define um meio de criar objetos dinâmicos como Javascript, devido a sua forte tipagem, por isso usei a estrutura de dicionário. O que acontece na verdade é que devolvemos uma coleção de funções que acessam os atributos do \u0026ldquo;construtor\u0026rdquo; através de closures.\u003c/p\u003e","title":"Python que nem Javascript!"},{"content":"O processo é bem simples, porém é necessário antes configurar algumas coisas no Google Cloud e gerar as credenciais necessárias, para este processo pode seguir este tutorial. Lembre-se também de criar uma variável de ambiente com o nome GOOGLE_APPLICATION_CREDENTIALS apontando para o caminho do json, no Linux basta fazer:\nexport GOOGLE_APPLICATION_CREDENTIALS=/caminho/para/arquivo.json\nDepois disso é possível executar o código abaixo (é claro, o bucket e o arquivo indicado deve existir):\nfrom datetime import timezone, datetime from typing import BinaryIO from google.cloud import storage def upload_file( data: BinaryIO, bucket: str, file_path: str, link_lifetime: int = 3600 ) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34; Função que realiza o upload do arquivo \u0026#34;\u0026#34;\u0026#34; storage_client = storage.Client() bucket = storage_client.bucket(bucket) blob = bucket.blob(file_path) blob.upload_from_file(data) # Faz o upload do arquivo binário e cria um objeto associado ao arquivo lifetime = int( datetime.now(tz=timezone.utc).timestamp() ) + link_lifetime # Gera um link para o arquivo com tempo de expiração url = blob.generate_signed_url(lifetime) return def main(): bucket = \u0026#39;meu-pequeno-bucket\u0026#39; # Bucket name in GCS file_name = \u0026#39;arquivo_legal.pdf\u0026#39; # Filename with open(file_name, \u0026#39;rb\u0026#39;) as f: url = upload_file( data=f, bucket=bucket, file_path=file_name, ) print(f\u0026#39;URL for file: {url}\u0026#39;) if __name__ == \u0026#34;__main__\u0026#34;: main() ","permalink":"https://blog.lucaspolo.dev/posts/fazendo-upload-de-arquivos-para-o-google-cloud-storage-com-python/","summary":"\u003cp\u003eO processo é bem simples, porém é necessário antes configurar algumas coisas no Google Cloud e gerar as credenciais necessárias, para este processo pode seguir \u003ca href=\"https://cloud.google.com/storage/docs/reference/libraries#client-libraries-install-python\"\u003eeste tutorial.\u003c/a\u003e Lembre-se também de criar uma variável de ambiente com o nome \u003cstrong\u003eGOOGLE_APPLICATION_CREDENTIALS\u003c/strong\u003e apontando para o caminho do json, no Linux basta fazer:\u003c/p\u003e\n\u003cp\u003eexport GOOGLE_APPLICATION_CREDENTIALS=/caminho/para/arquivo.json\u003c/p\u003e\n\u003cp\u003eDepois disso é possível executar o código abaixo (é claro, o bucket e o  arquivo indicado deve existir):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e datetime \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e timezone, datetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e typing \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e BinaryIO\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e google.cloud \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e storage\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eupload_file\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    data: BinaryIO, \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bucket: \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e, \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    file_path: \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    link_lifetime: \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eint\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#bd93f9\"\u003e3600\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) \u003cspan style=\"color:#ff79c6\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estr\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    Função que realiza o upload do arquivo\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    storage_client \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e storage\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eClient()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bucket \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e storage_client\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003ebucket(bucket)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    blob \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e bucket\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eblob(file_path)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    blob\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eupload_from_file(data)  \u003cspan style=\"color:#6272a4\"\u003e# Faz o upload do arquivo binário e cria um objeto associado ao arquivo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lifetime \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eint\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        datetime\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003enow(tz\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003etimezone\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003eutc)\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003etimestamp()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e link_lifetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Gera um link para o arquivo com tempo de expiração\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    url \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e blob\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003egenerate_signed_url(lifetime)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003emain\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bucket \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;meu-pequeno-bucket\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#6272a4\"\u003e# Bucket name in GCS\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    file_name \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;arquivo_legal.pdf\u0026#39;\u003c/span\u003e  \u003cspan style=\"color:#6272a4\"\u003e# Filename\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ewith\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eopen\u003c/span\u003e(file_name, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;rb\u0026#39;\u003c/span\u003e) \u003cspan style=\"color:#ff79c6\"\u003eas\u003c/span\u003e f:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        url \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e upload_file(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            data\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003ef, \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            bucket\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003ebucket, \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            file_path\u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003efile_name,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;URL for file: \u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e{\u003c/span\u003eurl\u003cspan style=\"color:#f1fa8c\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e__name__\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    main()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Fazendo upload de arquivos para o Google Cloud Storage com Python (versão de 2020)"},{"content":"Os dias não são fáceis, você acorda cedo e se desloca para o seu trabalho, então você faz algumas coisas e chega o fim do dia, você faz o caminho inverso para sua casa. No fim do mês você é pago por isso, o que é bom, e se for da área de TI, é \u0026ldquo;mais bom\u0026rdquo; do que 90% do restante do Brasil.\nAgora voltemos ao \u0026ldquo;faz algumas coisas\u0026rdquo; do paragrafo acima, que coisas são essas? Onde você aprendeu elas? Como lida com elas? Todas essas coisas são a sua profissão, mas o que é profissão? Será que é apenas o seu trabalho? Aquilo que você é pago para fazer? Vamos buscar a definição de profissão:\npro·fis·são (latim professio, -onis, declaração, manifestação, profissão, emprego, estado, ensino)\nsubstantivo feminino\n1. Declaração pública.\n2. Solenidade na qual alguém se liga por votos a uma ordem religiosa.\n3. Ofício; emprego; ocupação; mister.\n\u0026ldquo;profissões\u0026rdquo;, in Dicionário Priberam da Língua Portuguesa [em linha], 2008-2020, https://dicionario.priberam.org/profiss%C3%B5es [consultado em 05-01-2020].\nProfissão como declaração Como podemos ver acima, profissão vem do latim professio e significa declaração, manifestação, então a sua profissão é a sua declaração para o mundo, seu ofício. Isso deixou as coisas um pouco mais profundas do que apenas \u0026ldquo;aquilo que faço para ganhar dinheiro\u0026rdquo;. Inclusive não há na definição acima (pelo menos na etimologia da palavra) algo que ligue profissão a dinheiro, logo podemos ser profissionais sem ser remunerados (e também podemos ser amadores remunerados!).\nAssumindo essa nova visão mais profunda sobre a sua profissão, você gasta um pouco do seu tempo diário pensando no que você está declarando para o mundo através do seu trabalho? Você pensa em como fazer algo com qualidade, que agregue valor real para o mundo? Fazendo essa reflexão para a nossa área, a programação, fica claro que não faz parte da nossa rotina trazer essa reflexão para o nosso dia a dia (e isso está longe de ser ensinado em nossas escolas, mas isso é assunto para outro momento).\nA responsabilidade de quem programa As nossas responsabilidades como programadores são cada vez maiores, pois em um mundo onde a automação toma cada vez mais espaço, passamos de pessoas que criavam e geravam simples sistemas de cadastro e, quando muito, folhas de pagamento, para mantenedores de sistemas que movimentam milhões por semana, sistemas hospitalares (não só a ficha do paciente, mas também todo o suporte a vida de algumas UTIs) e a programação no mundo real através de robôs, carros autonômos, aviões e muito mais. Então precisamos fazer bem tudo isso, fazer nosso trabalho com qualidade, precisamos pensar sobre o que estamos fazendo, não apenas fazer. É necessário gastar um tempo pensando antes de qualquer decisão, se aquilo é a melhor forma de fazer, se irá ajudar as pessoas que prometemos ajudar e principalmente, se não irá prejudicar as pessoas que prometemos ajudar, tudo isso converge para um aspecto muito importante, a qualidade das nossas criações.\nDominar as ferramentas A qualidade de tudo o que fazemos está altamente correlacionada em como dominamos os meios pelo quais nos expressamos, da mesma forma que um marceneiro que usa com maestria suas ferramentas e cria coisas incríveis, um desenvolvedor que domina o computador com maestria também cria coisas incríveis, afinal a ferramenta para o artesão é como uma extensão para a sua mão e quando você quer fazer algo com a sua mão você não precisa pensar em quanto deve rotacionar seu pulso, a pressão que deve colocar nos dedos, etc., você só pensa no que deve ser feito e faz.\nParece ser muita responsabilidade e, pra falar a verdade, é. É necessário um esforço em forma de treino e prática a mais na sua rotina para que você domine essas ferramentas, seu computador, o servidor onde você roda suas aplicações, porém tudo isso vem com a sensação de que você está realmente no controle do que acontece, no controle da qualidade e principalmente no controle da sua carreira, que é parte essêncial da sua vida. E é claro, quando você tiver um domínio alto de todas as suas ferramentas e sua carreira, tudo isso para de ser uma barreira e permite você focar na sua parte criativa, participar de outras decisões (como de negócios) e também, quem sabe, se divertir mais com o seu trabalho.\nEssas são algumas reflexões que tirei do inicio da segunda ediçao do livro O Programador Pragmático, que já comentei em outro post.\n","permalink":"https://blog.lucaspolo.dev/posts/pense-sobre-o-seu-trabalho-o-programador-pragmatico/","summary":"\u003cp\u003eOs dias não são fáceis, você acorda cedo e se desloca para o seu trabalho, então você faz algumas coisas e chega o fim do dia, você faz o caminho inverso para sua casa. No fim do mês você é pago por isso, o que é bom, e se for da área de TI, é \u0026ldquo;mais bom\u0026rdquo; do que 90% do restante do Brasil.\u003c/p\u003e\n\u003cp\u003eAgora voltemos ao \u0026ldquo;faz algumas coisas\u0026rdquo; do paragrafo acima, que coisas são essas? Onde você aprendeu elas? Como lida com elas? Todas essas coisas são a sua profissão, mas o que é profissão? Será que é apenas o seu trabalho? Aquilo que você é pago para fazer? Vamos buscar a definição de profissão:\u003c/p\u003e","title":"Pense sobre o seu trabalho - O programador pragmático"},{"content":"from typing import List def quicksort(l: List): \u0026#34;\u0026#34;\u0026#34; Recebe uma lista de elementos e devolve eles ordenados \u0026#34;\u0026#34;\u0026#34; # Caso base! Nunca se esqueça disso em funções recursivas@ if not len(l): return l # Escolhemos um pivot, removemos ele da lista! # Reduzir a entrada também é essêncial! pivot = l.pop(0) # Separamos os elementos menores lower = [e for e in l if e \u0026lt;= pivot] # Separamos os maiores uppper = [e for e in l if e \u0026gt; pivot] # Os menores ficam na esquerda do pivo # Os maiores ficam na direita # Ai acontece a magia da recursão... # Ordedamos os menores e os maiores com a mesma função. return quicksort(lower) + [pivot] + quicksort(uppper) def main(): elems = [3,2,3,6,7,4,2,-1] print(quicksort(elems)) if __name__ == \u0026#39;__main__\u0026#39;: main() ","permalink":"https://blog.lucaspolo.dev/posts/drops-quicksort-em-python/","summary":"\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efrom\u003c/span\u003e typing \u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e List\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003equicksort\u003c/span\u003e(l: List):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    Recebe uma lista de elementos e devolve eles ordenados\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f1fa8c\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Caso base! Nunca se esqueça disso em funções recursivas@\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003elen\u003c/span\u003e(l):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e l\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Escolhemos um pivot, removemos ele da lista!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Reduzir a entrada também é essêncial!\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    pivot \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e l\u003cspan style=\"color:#ff79c6\"\u003e.\u003c/span\u003epop(\u003cspan style=\"color:#bd93f9\"\u003e0\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Separamos os elementos menores\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    lower \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e [e \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#ff79c6\"\u003ein\u003c/span\u003e l \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e e \u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;=\u003c/span\u003e pivot]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Separamos os maiores\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    uppper \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e [e \u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#ff79c6\"\u003ein\u003c/span\u003e l \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e e \u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e pivot]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Os menores ficam na esquerda do pivo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Os maiores ficam na direita\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Ai acontece a magia da recursão... \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#6272a4\"\u003e# Ordedamos os menores e os maiores com a mesma função.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ereturn\u003c/span\u003e quicksort(lower) \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e [pivot] \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e quicksort(uppper)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003emain\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    elems \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e6\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e7\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e4\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e,\u003cspan style=\"color:#ff79c6\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(quicksort(elems))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003e__name__\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#39;__main__\u0026#39;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    main()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Drops: Quicksort em Python"},{"content":"Disclaimer: Este post é o primeiro de uma série sobre o livro O Programador Pragmático, tratando sobre a primeira edição, caso deseje compra-lo dá uma conferida no último parágrafo (o que já irá acontecer se você ler o post inteiro).\nDurante nossas carreiras existem alguns momentos enigmáticos que nos fazem refletir sobre o que realmente queremos para o nosso futuro, sobre o profissional que queremos ser e como iremos nos portar pelos próximos anos. Tais momentos são motivados por diversos fatores, como um perrengue no trabalho, um professor que sabe te direcionar, a comunidade, ou como é no caso, um livro.\nNo ano de 2011 iniciei a minha jornada profissional como programador, já havia lido alguns títulos técnicos, mas estava longe de ser o que consideramos um bom profissional. Havia muito o que aprender para poder ter mais autonomia e confiança, tanto tecnicamente como comportamentalmente. Durante minhas perambulações pela livraria Cultura do Conjunto Nacional passei pela área de informática e esbarrei em um livro interessante, O Programador Pragmático de Andrew Hunt e David Thomas. Folheando vi diversos temas que esbarram no técnico, mas tinham uma visão mais geral, trazendo uma lista de competências que nós, programadores, deveríamos desenvolver para sermos profissionais mais pragmáticos.\nO livro é bem direto em seus pontos, abordando assuntos diversos e algumas novidades para um jovem programador que já em 2011 não sabia o que estudar devido a enxurrada de informação da época (e olha que a onda do novo framework de Javascript por segundo ainda estava por vir). A estrutura do livro é em capítulos-tópicos, curtos e bem objetivos. Os temas são variados, passam pelo teste unitário e sua importância, como estruturar o código e princípios de boa engenharia de software, ferramentas que devemos dominar e chegando no ponto sobre gestão de projetos ágeis (tanto o Andrew quando o David são signatários do Manifesto Ágil)\nEle realmente me impactou no que diz respeito sobre o que é um software de qualidade e principalmente a qualidade de um profissional de programação. A abertura para assuntos que eu nunca tinha visto antes, como expressões regulares, testes unitários, manipulação de textos e domínio da linha de comando já fez a minha cabeça abrir para diversos assuntos, fazendo eu ter que lidar com linguagens antigas porém muito poderosas em suas premissas (a edição brasileira é de 2010, mas na verdade o livro data de 1999) como Smalltalk e Perl.\nConfesso que li mais rápido do que deveria, pois este não é um livro que você simplesmente passa por suas páginas e tem uma fácil absorção, principalmente se você for tão amador quanto eu era na época. Ele propõe diversas ideias com muitos exemplos e não deixa passar em branco seu aprendizado no final dos capítulos, propondo exercícios e reflexões sobre problemas e casos relacionados ao tema. Revisitei o livro diversas vezes durante os anos seguintes e sempre aprendia algo novo, fazendo seus exemplos, levando para o meu trabalho diário o que estava aprendendo dele.\nNão caberia neste post falar sobre todos os tópicos do livro e logo iniciarei uma jornada mais detalhada pelos capítulos da segunda edição lançada este ano, sendo assim vou deixar para uma resenha mais completa passar por tais tópicos. Novos tópicos foram adicionados na segunda edição (como uma seção inteira sobre concorrência e seus modelos), além de outros que foram encolhidos ou removidos (como geração de código pois com o avanço das abstrações em linguagens de programação não se fazem necessárias na mesma escala de outrora).\nCaso queira adquirir o livro recomendo começar realmente pela segunda edição, mas caso não consiga vale ler a primeira edição emprestada ou quem sabe procurá-la em sebos, pois mesmo com linguagens e algumas tecnologias antigas, seus conceitos ainda são muito sólidos e valiósos.\n","permalink":"https://blog.lucaspolo.dev/posts/o-caminho-do-programador-pragmatico-um-pouco-sobre-a-primeira-edicao-do-programa/","summary":"\u003cp\u003e\u003cem\u003eDisclaimer\u003c/em\u003e: Este post é o primeiro de uma série sobre o livro O Programador Pragmático, tratando sobre a primeira edição, caso deseje compra-lo dá uma conferida no último parágrafo (o que já irá acontecer se você ler o post inteiro).\u003c/p\u003e\n\u003cp\u003eDurante nossas carreiras existem alguns momentos enigmáticos que nos fazem refletir sobre o que realmente queremos para o nosso futuro, sobre o profissional que queremos ser e como iremos nos portar pelos próximos anos. Tais momentos são motivados por diversos fatores, como um perrengue no trabalho, um professor que sabe te direcionar, a comunidade, ou como é no caso, um livro.\u003c/p\u003e","title":"O caminho do programador (pragmático) - Um pouco sobre a primeira edição do Programador Pragmático"},{"content":"Uma das formas de lidar com processamento assíncrono no Python (e diversas outras linguagens) sem a necessidade de usar threads e afins é utilizando filas e tasks (que são aplicações que rodam conforme demanda, em um processamento similar a batches).\nPara isso o Python dispõe de uma biblioteca chamada Celery, que de uma maneira bem simples permite realizar o processamento assíncrono. Explicando de uma maneira simples, ao invocar uma função, ao invés de executar seu código, o Celery pega os parâmetros e mais algumas meta-informações da chamada e coloca numa fila, enquanto isso, em outro lugar (processo, computador ou continente), o Celery captura as mensagens desta fila e dispara as tasks. Aqui está uma implementação básica de uma task que soma dois valores:\nimport cachelock from celery import Celery app = Celery(\u0026#39;tasks\u0026#39;) app.config_from_object(\u0026#39;celeryconfig\u0026#39;) @app.task(queue=\u0026#39;test-celery\u0026#39;) @cachelock.once( key=\u0026#39;add-{x}-{y}\u0026#39;, raise_if_lock=True ) def add(x, y): return x + y Primeiro criamos a instância app Celery e dizemos qual módulo está a configuração. Perceba que a função foi anotada com o decorator @app.task(queue=\u0026lsquo;test-celery), que já faz a função ser gerenciada pelo Celery, o parâmetro queue serve para indicar qual a fila que deverá ser utilizada para isto.\nA configuração também é simples:\nimport urllib.parse from kombu import Exchange, Queue from decouple import config aws_access_key_id=config(\u0026#39;AWS_ACCESS_KEY_ID\u0026#39;) aws_secret_key=config(\u0026#39;AWS_SECRET_KEY\u0026#39;) broker_url = \u0026#39;sqs://{0}:{1}@\u0026#39;.format( urllib.parse.quote(aws_access_key_id, safe=\u0026#39;\u0026#39;), urllib.parse.quote(aws_secret_key, safe=\u0026#39;\u0026#39;) ) task_queues = ( Queue( \u0026#39;test-celery\u0026#39;, Exchange(\u0026#39;test-celery\u0026#39;) ), ) Nele configuramos o broker_url (com ID e secret do usuário com acesso programático ao SQS), que indica qual broker (gestor de fila) utilizaremos (no nosso exemplo usamos o SQS, porém o Celery dá melhor suporte e com mais funcionalidades no RabbitMQ e Redis). Também configuramos as filas que utilizaremos em task_queues, senão será usada a fila padrão (celery).\nApós isso podemos executar o Celery:\ncelery -A tasks worker \u0026ndash;loglevel=info\nE assim podemos invocar a função (em outro terminal ou até mesmo em outro computador com o mesmo projeto), porém chamamos ela através do método .delay(parâmetros):\nfrom tasks import add for i in range(100): add.delay(i, i) Assim a função será invocada através do Celery. Um desenho da arquitetura deste pequeno projeto pode ser visto aqui:\nCaso queira baixar este código de uma vez só e instalar suas dependências, confira aqui no Github.\nObs: O CacheLock que você viu ajuda a não ter a possibilidade uma mesma mensagem ser consumida por duas tasks ao mesmo tempo.\n","permalink":"https://blog.lucaspolo.dev/posts/utilzando-celery-junto-com-o-sqs/","summary":"\u003cp\u003eUma das formas de lidar com processamento assíncrono no Python (e diversas outras linguagens) sem a necessidade de usar threads e afins é utilizando filas e tasks (que são aplicações que rodam conforme demanda, em um processamento similar a batches).\u003c/p\u003e\n\u003cp\u003ePara isso o Python dispõe de uma biblioteca chamada Celery, que de uma maneira bem simples permite realizar o processamento assíncrono. Explicando de uma maneira simples, ao invocar uma função, ao invés de executar seu código, o Celery pega os parâmetros e mais algumas meta-informações da chamada e coloca numa fila, enquanto isso, em outro lugar (processo, computador ou continente), o Celery captura as mensagens desta fila e dispara as tasks. Aqui está uma implementação básica de uma task que soma dois valores:\u003c/p\u003e","title":"Utilizando Celery junto com o SQS"},{"content":"O terminal é uma das ferramentas mais poderosas que temos ao manipular informações no computador, desde o desenvolvimento de software até o hacking, passando por manipulação de texto, administração de sistemas e também para algumas brincadeiras. O acesso ao terminal é simples quando você está dentro de um Linux no computador (e até no Windows agora), porém nem sempre temos um notebook por perto, que por mais que seja portátil, não é simples de carregar por ai. Então, nas pesquisas pela internet, buscando uma alternativa para o tablet e smartphone, eu encontrei o Termux.\nO Termux emula um terminal dentro do seu Android, porém ao contrário de alguns aplicativo que apenas emulam alguns comandos, ele tem um sistema completo de terminal, ainda permitindo instalar pacotes de maneira similar ao Debian:\nInstalando um pacote do sistema com o comando apk install\nAproveitando todo esse poder, também instalei o Python 3.7.2 e diversas dependências de bibliotecas de sistema (openssl-dev, libffi-dev e etc) junto com o Git e clonei um projeto do Github. A aplicação funcionou normalmente, sendo um bot para Telegram que faz scrap da API do Reddit, usando as libs telegram-bot, requests e click, além de outras dependências como pytest, pytest-cov e muito mais. Você pode conferir o projeto aqui.\nRodando os testes junto com a cobertura\nUma das limitações que percebi no Termux, que na verdade é uma limitação do Android, é que como ele não permite a criação de links simbólicos no sistema e a definição de executáveis (o que acredito que ser fácil de superar quando o aparelho está \u0026ldquo;rooteado\u0026rdquo;), você não pode criar virtualenv\u0026rsquo;s dentro do sistema, o que pode ser facilmente ser superado pelo fato de você criar suas virtualenv\u0026rsquo;s na home do Termux.\n","permalink":"https://blog.lucaspolo.dev/posts/usando-terminal-e-programando-em-python-no-android/","summary":"\u003cp\u003eO terminal é uma das ferramentas mais poderosas que temos ao manipular informações no computador, desde o desenvolvimento de software até o hacking, passando por manipulação de texto, administração de sistemas e também para algumas brincadeiras. O acesso ao terminal é simples quando você está dentro de um Linux no computador (e até no Windows agora), porém nem sempre temos um notebook por perto, que por mais que seja portátil, não é simples de carregar por ai. Então, nas pesquisas pela internet, buscando uma alternativa para o tablet e smartphone, eu encontrei o \u003ca href=\"https://termux.com/\"\u003eTermux\u003c/a\u003e.\u003c/p\u003e","title":"Usando terminal e programando em Python no Android"},{"content":"Ultimamente tenho me interessado cada vez mais em como linguagens de programação funcionam e encontrei um material bem legal, simples e prático para ajudar nos estudos. É um artigo do Peter Norvig sobre como criar um interpretador de Scheme em Python, confira: http://norvig.com/lispy.html\n","permalink":"https://blog.lucaspolo.dev/posts/construindo-um-interpretador-de-lisp-em-python/","summary":"\u003cp\u003eUltimamente tenho me interessado cada vez mais em como linguagens de programação funcionam e encontrei um material bem legal, simples e prático para ajudar nos estudos. É um artigo do Peter Norvig sobre como criar um interpretador de Scheme em Python, confira: \u003ca href=\"http://norvig.com/lispy.html\"\u003ehttp://norvig.com/lispy.html\u003c/a\u003e\u003c/p\u003e","title":"Construindo um interpretador de Lisp em Python"},{"content":"Durante o processo de desenvolvimento de software é comum que ao criarmos mais código, possamos enviar ele para o repositório de código, assim os colegas podem acompanhar o que está sendo alterado e também você criar um backup de suas informação.\nMas surge uma dúvida na cabeça do programador: qual é o mínimo de código que deve criar antes de realizar um commit? Uma linha? Duas? Cem? Fica complexo definir isso, pois se criarmos muitos commits a nossa funcionalidade nova não fica atômica, mas se demorarmos para commitar e enviar para o repositório, corremos o risco de criar um commit grande demais para review, além é claro do risco de perder o código local.\nPara ajudar nisso, o git possui uma funcionalidade muito interessante, o git squash, que permite que você agrupe seus commits já realizados, podendo assim criar commits mais organizados.\nVamos supor que você criou seu arquivo de teste unitário, comitou esta alteração e deseja já deixa-la no repositório remoto (na sua branch específica, é claro) como backup:\ngit add test_nova_funcionalidade.py git commit -m \u0026#34;Teste unitário da nova funcionalidade\u0026#34; git push origin nova_funcionalidade Despois de criar os testes, obviamente você irá criar a funcionalidade:\ngit add nova_funcionalidade.py git commit -m \u0026#34;Nova funcionalidade implementada\u0026#34; git push origin nova_funcionalidade Além disso, você descobriu que precisa ajustar um outro arquivo já existente, para dar suporte a sua alteração, no nosso caso, vamos ajustar nosso README.md:\ngit add README.md git commit -m \u0026#34;Alterado o README.md\u0026#34; git push origin nova_funcionalidade Agora tudo está concluído, vamos ver como as coisas ficaram lá no Github:\nPerceba que existem três commits, porém como a nossa funcionalidade é única, queremos criar algo atômico para agruapar estas alterações e neste ponto entra o git squash.\nIremos agrupar os commits reescrevendo o histórico de nossos últimos 3 commits, para isso precisaremos usar o comando:\ngit rebase -i HEAD~3 Nisto será aberto uma tela listando nossos últimos três commits:\npick b755797 Teste unitário da nova funcionalidade pick 8a7064e Nova funcionalidade implementada pick fdc8f9b Alterado o README.md # Rebase 8c0eaf4..fdc8f9b onto 8c0eaf4 (3 commands) Iremos deixar apenas o primeiro da lista como está e iremos alterar o pick para squash:\npick b755797 Teste unitário da nova funcionalidade squash 8a7064e Nova funcionalidade implementada squash fdc8f9b Alterado o README.md Assim salvamos a nossa alteração e abrirá uma nova tela onde podemos digitar uma nova mensagem (esta já virá com todas as mensagens dos commits anteriores, que podem ser apagados). Colocarei uma mensagem que resume tudo o que foi feito:\nCriada nova funcionalidade - Criado teste unitário - Criada funcionalidade - Alterado README.md Agora salvamos e temos o nosso novo commit:\n[detached HEAD 1543120] Criada nova funcionalidade Date: Sun Jan 6 22:09:46 2019 -0200 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 nova_funcionalidade.py create mode 100644 test_nova_funcionalidade.py Successfully rebased and updated refs/heads/nova_funcionalidade. Podemos fazer o push forçado (pois será necessário reescrever o histórico):\ngit push -f origin nova_funcionalidade E agora ao verificar novamente no Github, vemos apenas um único commit com todas as alterações:\nAssim o Pull Request fica bem mais simples, e caso necessário, você pode retornar a versão apenas um único commit.\n","permalink":"https://blog.lucaspolo.dev/posts/git-squash-agregando-seus-commits-em-um-so/","summary":"\u003cp\u003eDurante o processo de desenvolvimento de software é comum que ao criarmos mais código, possamos enviar ele para o repositório de código, assim os colegas podem acompanhar o que está sendo alterado e também você criar um backup de suas informação.\u003c/p\u003e\n\u003cp\u003eMas surge uma dúvida na cabeça do programador: qual é o mínimo de código que deve criar antes de realizar um commit? Uma linha? Duas? Cem? Fica complexo definir isso, pois se criarmos muitos commits a nossa funcionalidade nova não fica atômica, mas se demorarmos para commitar e enviar para o repositório, corremos o risco de criar um commit grande demais para review, além é claro do risco de perder o código local.\u003c/p\u003e","title":"Git Squash: Agregando seus commits em um só!"},{"content":"Uma das coisas mais interessantes do Python é como ele interage com as suas estruturas de dados padrão, sendo um dos exemplos mais interessantes o desempacotamento de listas e dicionários. A situação é simples, vamos supor que você tenha uma lista de parâmetros e deseja passar para uma função, podemos testar a seguinte situação:\ndef funcao(parametro1, parametro2, parametro3): print(parametro1, parametro2, parametro3) parametros = [1,2,3] funcao(parametros) Mas temos o seguinte erro:\nTypeError: funcao() missing 2 required positional arguments: \u0026lsquo;parametro2\u0026rsquo; and \u0026lsquo;parametro3\u0026rsquo;\nIsso ocorre pois a lista é enviada para o parametro1, deixando os outros parâmetros vazios. Para resolvermos isso o Python nos fornece uma sintaxe que permite desempacotar os valores para enviar como parâmetro, utilzando * e ** (este último para dicionários).\nMuitas vezes você irá ver por ai a seguinte sintaxe:\ndef funcao(parametro1, parametro2, parametro3): print(parametro1, parametro2, parametro3) parametros = [\u0026#34;Spam\u0026#34;, \u0026#34;Spam\u0026#34;, \u0026#34;Spam\u0026#34;] funcao(*parametros) Se você quiser enviar os parâmetros de maneira nomeada (para poder trocar a ordem deles), você pode utilizar um dicionário para desempacotar:\ndef funcao(parametro1, parametro2, parametro3): print(parametro1, parametro2, parametro3) parametros = { \u0026#39;parametro1\u0026#39;: \u0026#39;1\u0026#39;, \u0026#39;parametro2\u0026#39;: \u0026#39;2\u0026#39;, \u0026#39;parametro3\u0026#39;: \u0026#39;3\u0026#39;, } funcao(**parametros) Esta solução é muito útil para diversas situações, como deixar a chamada de uma função com muitos parâmetros mais limpa, construir os parâmetros no decorrer do código para só chamar ao final e até criar dinâmicamente os parâmetros:\n# Função com muitos parâmetros def funcao(parametro1, parametro2, parametro3, parametro4, parametro5, parametro6): print(parametro1, parametro2, parametro3) print(parametro4, parametro5, parametro6) # Construindo parâmetros parametros = { \u0026#39;parametro1\u0026#39;: 1, \u0026#39;parametro2\u0026#39;: 2, \u0026#39;parametro3\u0026#39;: 3, \u0026#39;parametro4\u0026#39;: 4, \u0026#39;parametro5\u0026#39;: 5, \u0026#39;parametro6\u0026#39;: 6, } # Chamando passando parâmetros desempacotados funcao(**parametros) # Criando parâmetros dinamicamente! funcao(**{f\u0026#34;parametro{i}\u0026#34;: i for i in range(1, 7)}) ","permalink":"https://blog.lucaspolo.dev/posts/desempacotando-parametros-em-python/","summary":"\u003cp\u003eUma das coisas mais interessantes do Python é como ele interage com as suas estruturas de dados padrão, sendo um dos exemplos mais interessantes o desempacotamento de listas e dicionários. A situação é simples, vamos supor que você tenha uma lista de parâmetros e deseja passar para uma função, podemos testar a seguinte situação:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003efuncao\u003c/span\u003e(parametro1, parametro2, parametro3):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eprint\u003c/span\u003e(parametro1, parametro2, parametro3)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eparametros \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#bd93f9\"\u003e1\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e2\u003c/span\u003e,\u003cspan style=\"color:#bd93f9\"\u003e3\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003efuncao(parametros)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eMas temos o seguinte erro:\u003c/p\u003e","title":"Desempacotando parâmetros em Python"},{"content":" ","permalink":"https://blog.lucaspolo.dev/posts/um-pouco-sobre-calculo-lambda/","summary":"\u003cdiv style=\"position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;\"\u003e\n      \u003ciframe allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen\" loading=\"eager\" referrerpolicy=\"strict-origin-when-cross-origin\" src=\"https://www.youtube.com/embed/eis11j_iGMs?autoplay=0\u0026amp;controls=1\u0026amp;end=0\u0026amp;loop=0\u0026amp;mute=0\u0026amp;start=0\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;\" title=\"YouTube video\"\u003e\u003c/iframe\u003e\n    \u003c/div\u003e","title":"Um pouco sobre cálculo lambda"},{"content":"Quando programamos em Python é importante verificarmos se o nosso código está de acordo com a PEP 8, seguindo seu guia de estilos. Para isto muitas vezes rodamos o Flake8, que é uma aplicação que analisa o nosso código e avalia o que está seguindo e não está seguindo as boas práticas da PEP 8.\nPara instalar o Flake8 é muito simples, basta rodarmos o comando:\npip install flake8\nApós instalarmos para podermos avaliar nosso código no diretório atual basta executarmos o comando:\nflake8 .\ne ele retornará com as melhorias a serem feitas no código.\nFacilitando mais ainda nosso fluxo de trabalho, é possível também através dos hooks do Git executar o flake8 sempre antes de cada commit, e caso apresente algum erro ele não deixará o commit prosseguir sem realizar as correções necessárias: Para instalar o hook primeiro rode o seguinte comando:\nflake8 \u0026ndash;install-hook git\nDepois é necessário ativa-lo rodando o simples comando:\ngit config \u0026ndash;bool flake8.strict true\nAssim, sempre antes de cada commit ele irá executar o Flake8 avaliando o código.\n","permalink":"https://blog.lucaspolo.dev/posts/rodando-automaticamente-o-flake8-antes-de-todos-os-commits-do-git/","summary":"\u003cp\u003eQuando programamos em Python é importante verificarmos se o nosso código está de acordo com a \u003ca href=\"https://www.python.org/dev/peps/pep-0008/?\"\u003ePEP 8\u003c/a\u003e, seguindo seu guia de estilos. Para isto muitas vezes rodamos o \u003ca href=\"http://flake8.pycqa.org/en/latest/\"\u003eFlake8\u003c/a\u003e, que é uma aplicação que analisa o nosso código e avalia o que está seguindo e não está seguindo as boas práticas da PEP 8.\u003c/p\u003e\n\u003cp\u003ePara instalar o Flake8 é muito simples, basta rodarmos o comando:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003epip install flake8\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eApós instalarmos para podermos avaliar nosso código no diretório atual basta executarmos o comando:\u003c/p\u003e","title":"Rodando automaticamente o Flake8 antes de todos os commits do Git"},{"content":"Apesar da grande adoção de REST para a criação de webservices, ainda é muito comum (e necessário) termos que trocar mensagens com sistemas legados, inclusive em outras linguagens como Java e .NET, assim poder fazer em chamadas a endpoints SOAP se torna necessário muitas vezes.\nEsta necessidade surgiu para mim quando vi que testar serviços em SOAP seria muito mais fácil ser feito em Python, devido sua sintaxe idiomática e scripts muito simples de serem construídos. Buscando nas \u0026ldquo;internets\u0026rdquo; eu descobri uma biblioteca chamada Zeep, que de tão simples que é o seu acesso não compensa nem discutir muito, mas já irmos direto ao código, utilizando o webservice dos Correios:\nfrom zeep import Client client = Client(\u0026#34;http://ws.correios.com.br/calculador/CalcPrecoPrazo.asmx?WSDL\u0026#34;) # Essa chamada retorna uma list de dicts, bem interessante. # Se a entrada puder ser uma lista você poderá usar uma abordagem semelhante servicos = client.service.ListaServicos() print(servicos) #Testando chamada com entrada com mais de um parametro. entrada = { \u0026#39;nCdServico\u0026#39; : 40010, \u0026#39;sCepOrigem\u0026#39; : \u0026#39;01217010\u0026#39;, \u0026#39;sCepDestino\u0026#39; : \u0026#39;69005000\u0026#39; } #Calculando o prazo de entrega para SEDEX #Alguns serviços que já chamei aceitam o dicionario diretamente, # mas este no caso foi necessário desempacotar, senão ele dá erro. retorno = client.service.CalcPrazo(**entrada) print(retorno) Como podemos ver, é tudo muito simples, basta criarmos um objeto do tipo Client passando a string do WSDL e através de services temos acessos ao métodos do serviço. Tendo a necessidade de inspecionar o serviço podemos rodar o seguinte comando:\npython -m zeep http://ws.correios.com.br/calculador/CalcPrecoPrazo.asmx?WSDL Retornando assim os tipos e as operações do serviço.\n","permalink":"https://blog.lucaspolo.dev/posts/acessando-webservices-soap-em-python/","summary":"\u003cp\u003eApesar da grande adoção de REST para a criação de webservices, ainda é muito comum (e necessário) termos que trocar mensagens com sistemas legados, inclusive em outras linguagens como Java e .NET, assim poder fazer em chamadas a endpoints SOAP se torna necessário muitas vezes.\u003c/p\u003e\n\u003cp\u003eEsta necessidade surgiu para mim quando vi que testar serviços em SOAP seria muito mais fácil ser feito em Python, devido sua sintaxe idiomática e scripts muito simples de serem construídos. Buscando nas \u0026ldquo;internets\u0026rdquo; eu descobri uma biblioteca chamada \u003ca href=\"http://docs.python-zeep.org/en/master/\"\u003eZeep\u003c/a\u003e, que de tão simples que é o seu acesso não compensa nem discutir muito, mas já irmos direto ao código, utilizando o webservice dos Correios:\u003c/p\u003e","title":"Acessando webservices SOAP em Python"},{"content":"Programar em Java está cada vez mais rápido e simples, desde as mudanças que começaram a surgir na versão 7 do Java, a verbosidade característica da linguagem foi reduzindo e agora no Java 8 alcançamos um nível muito superior com a programação funcional presente na linguagem.\nPorém, muitos ainda dizem que estas funcionalidades chegaram um pouco atrasadas na linguagem, e durante este tempo que ainda não tinhamos a programação funcional presente no Java, foram surgindo outras linguagens sobre a JVM que visavam trazer novos paradigmas para os programadores.\nComo estamos acompanhando, o Javascript tem tomado cada vez mais conta dos projetos de desenvolvimento mudo afora, principalmente agora ele roda firme e forte no lado do servidor, através de diversos projetos diferentes, sendo a referência maior o Node.js, com isto, novamente o Javascript ganhou o foco, principalmente após a criação da instrução invokedynamic, que permitiu a criação e invocação de métodos durante a execução do programa.\nAssim, a comunidade iniciou um novo projeto, o Nashorn, que permite executar Javascript na JVM, dentro de outros programas em Java e também executar Java dentro de Javascript. Pode parecer loucura, mas é muito simples iniciar o desenvolvimento, como vemos abaixo.\nA primeira coisa que notamos, é que além de rodar scripts, foi criado um interpretador interativo, onde você digita os comandos e recebe o resultado na hora, similar aos já existentes em Python e Ruby. Para acessa-lo basta digitar o comando jrunscript:\nNote que alguns comandos já executam normalmente, como o print, criação de variáveis e também operações aritméticas. Porém, não temos apenas o interpretador interativo, podemos executar diretamente scripts, bastando colocar no prompt jrunscript seuarquivo.js, vejamos um exemplo:\nvar imprimeNumeros = function(numeros) { for(var n = 0; n \u0026lt; numeros.length; n++) { println(numeros[n]); } }; imprimeNumeros([1,2,3]); Este script simples apenas imprime alguns números na tela, porém já podemos ver como diversos elementos do Javascript atuam em execução, sendo a saída:\nMas não se limita apenas a operadores básicos da linguagem, como o script roda sobre a máquina virtual Java, ou seja, ele é convertido em bytecodes, também podemos invocar bytecodes já existentes, ou seja, invocar classes presentes na linguagem Java, como este exemplo que invoca a classe FileReader e Scanner, lendo e exibindo as linhas de um arquivo:\nvar file = new java.io.FileReader(\u0026#34;nomes.txt\u0026#34;); var scanner = new java.util.Scanner(file); scanner.forEachRemaining(function(linha) { print(linha); }); Perceba como escrevemos muito pouco código para realizar tarefas interessantes, tudo isso através de uma linguagem familiar e simples, porém com muitos recursos em sua sintaxe.\n","permalink":"https://blog.lucaspolo.dev/posts/nashorn-javascript-sobre-a-jvm/","summary":"\u003cp\u003eProgramar em Java está cada vez mais rápido e simples, desde as mudanças que começaram a surgir na versão 7 do Java, a verbosidade característica da linguagem foi reduzindo e agora no Java 8 alcançamos um nível muito superior com a programação funcional presente na linguagem.\u003c/p\u003e\n\u003cp\u003ePorém, muitos ainda dizem que estas funcionalidades chegaram um pouco atrasadas na linguagem, e durante este tempo que ainda não tinhamos a programação funcional presente no Java, foram surgindo outras linguagens sobre a JVM que visavam trazer novos paradigmas para os programadores.\u003c/p\u003e","title":"Nashorn: Javascript sobre a JVM"},{"content":"Quando estamos nas aulas iniciais de programação, aprendemos a iterar sobre vetores e matrizes, sendo que no segundo caso é necessário criar um loop (for, while e etc) para cada dimensão de nossa matriz. Desta forma criamos muitas vezes um código com vários níveis de aninhamento no nosso código.\nUma outra forma de lidar com isto é criando uma forma de a partir de um único índice extrair o valores dos sub-índices, uma tarefa simples se utilizarmos módulo.\nComo podemos ver no código abaixo, iteramos sobre um vetor primeiro extraindo o índice do vetor interior e logo na sequência extraímos o índice do vetor principal. Iteramos duas vezes (distintas), uma para preencher os valores e a outra para imprimir os valores. Tudo muito simples e com apenas uma variável.\npublic static void matriz() { int [][] vetor = new int[5][5]; int tamanhoVetor = vetor.length; int tamanhoSubVetor = vetor[1].length; int tamanho = tamanhoVetor * tamanhoSubVetor; for(int i = 0; i \u0026lt; tamanho; i++) { int indiceDoSubvetor = i % tamanhoVetor; int indiceDoVetor = (i - indiceDoSubvetor) / tamanhoSubVetor; System.out.println(\u0026#34;Vetor: \u0026#34; + indiceDoVetor + \u0026#34; Subvetor: \u0026#34; + indiceDoSubvetor); vetor[indiceDoVetor][indiceDoSubvetor] = i; } for(int i = 0; i \u0026lt; tamanho; i++) { int indiceDoSubvetor = i % tamanhoSubVetor; int indiceDoVetor = (i - indiceDoSubvetor) / tamanhoVetor; System.out.println(vetor[indiceDoVetor][indiceDoSubvetor]); } } ","permalink":"https://blog.lucaspolo.dev/posts/iterando-sobre-uma-matriz-com-um-unico-loop/","summary":"\u003cp\u003eQuando estamos nas aulas iniciais de programação, aprendemos a iterar sobre vetores e matrizes, sendo que no segundo caso é necessário criar um loop (for, while e etc) para cada dimensão de nossa matriz. Desta forma criamos muitas vezes um código com vários níveis de aninhamento no nosso código.\u003c/p\u003e\n\u003cp\u003eUma outra forma de lidar com isto é criando uma forma de a partir de um único índice extrair o valores dos sub-índices, uma tarefa simples se utilizarmos módulo.\u003c/p\u003e","title":"Iterando sobre uma matriz com um único loop"},{"content":"Uma pequena forma de como usar o Migre.me dentro de sua aplicação para encurtar URLs. A requisição é feita utilizando alguns componentes da especificação JAX-RS, utilizando o Jersey como implementação.\nPara fazer parser do JSON recebido, utilizamos o Jackson, o que deixa as coisas muito simples.\npackage br.com.lucaspolo.json.teste; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import javax.naming.LimitExceededException; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Link; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; /** * @author lucaspolo * Classe de teste que faz a requisição do migre.me, encurta a URL e converte em um Hash. * A dica do parser para Map foi retirada de * {@link http://www.mkyong.com/java/how-to-convert-java-map-to-from-json-jackson/} * O POM com as dependencias do Maven para rodar este exemplo é este * {@link https://gist.github.com/lucaspolo/7a2a0ea33f3ce0c93975} */ public class App { public static void main( String[] args ) throws Exception { URI uri = new URI(\u0026#34;http://migre.me/api.json?\u0026#34;); Client client = ClientBuilder.newClient(); WebTarget target = client.target(uri.toURL().toString()) .queryParam(\u0026#34;url\u0026#34;, \u0026#34;http://www.ocaminhodoprogramador.com.br\u0026#34;); String conteudo = target.request().get(String.class); System.out.println(conteudo); Map\u0026lt;String, String\u0026gt; map = new HashMap\u0026lt;\u0026gt;(); ObjectMapper mapper = new ObjectMapper(); map = mapper.readValue(conteudo, new TypeReference\u0026lt;HashMap\u0026lt;String, String\u0026gt;\u0026gt;() {}); System.out.println(map.get(\u0026#34;migre\u0026#34;)); } } ","permalink":"https://blog.lucaspolo.dev/posts/encurtando-links-em-java-usando-o-migre-me/","summary":"\u003cp\u003eUma pequena forma de como usar o \u003ca href=\"http://migre.me/\"\u003eMigre.me\u003c/a\u003e dentro de sua aplicação para encurtar URLs. A requisição é feita utilizando alguns componentes da especificação JAX-RS, utilizando o Jersey como implementação.\u003c/p\u003e\n\u003cp\u003ePara fazer parser do JSON recebido, utilizamos o Jackson, o que deixa as coisas muito simples.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003epackage\u003c/span\u003e br.com.lucaspolo.json.teste;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e java.net.URI;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e java.net.URISyntaxException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e java.util.HashMap;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e java.util.Map;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e javax.naming.LimitExceededException;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e javax.ws.rs.client.Client;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e javax.ws.rs.client.ClientBuilder;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e javax.ws.rs.client.WebTarget;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e javax.ws.rs.core.Link;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e org.codehaus.jackson.map.ObjectMapper;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003eimport\u003c/span\u003e org.codehaus.jackson.type.TypeReference;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e * @author lucaspolo\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e * Classe de teste que faz a requisição do migre.me, encurta a URL e converte em um Hash.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e * A dica do parser para Map foi retirada de \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e * {@link http://www.mkyong.com/java/how-to-convert-java-map-to-from-json-jackson/}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e * O POM com as dependencias do Maven para rodar este exemplo é este \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e * {@link https://gist.github.com/lucaspolo/7a2a0ea33f3ce0c93975}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#6272a4\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003eApp\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003epublic\u003c/span\u003e \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003estatic\u003c/span\u003e \u003cspan style=\"color:#8be9fd\"\u003evoid\u003c/span\u003e \u003cspan style=\"color:#50fa7b\"\u003emain\u003c/span\u003e( String\u003cspan style=\"color:#ff79c6\"\u003e[]\u003c/span\u003e args ) \u003cspan style=\"color:#8be9fd;font-style:italic\"\u003ethrows\u003c/span\u003e Exception\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tURI uri \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e URI(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://migre.me/api.json?\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tClient client \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e ClientBuilder.\u003cspan style=\"color:#50fa7b\"\u003enewClient\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tWebTarget target \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e client.\u003cspan style=\"color:#50fa7b\"\u003etarget\u003c/span\u003e(uri.\u003cspan style=\"color:#50fa7b\"\u003etoURL\u003c/span\u003e().\u003cspan style=\"color:#50fa7b\"\u003etoString\u003c/span\u003e())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t.\u003cspan style=\"color:#50fa7b\"\u003equeryParam\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;url\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;http://www.ocaminhodoprogramador.com.br\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tString conteudo \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e target.\u003cspan style=\"color:#50fa7b\"\u003erequest\u003c/span\u003e().\u003cspan style=\"color:#50fa7b\"\u003eget\u003c/span\u003e(String.\u003cspan style=\"color:#50fa7b\"\u003eclass\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tSystem.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(conteudo);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\tMap\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eString, String\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e map \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e HashMap\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u0026gt;\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ObjectMapper mapper \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e ObjectMapper();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        map \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e mapper.\u003cspan style=\"color:#50fa7b\"\u003ereadValue\u003c/span\u003e(conteudo, \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e TypeReference\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eHashMap\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eString, String\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e() {});\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(map.\u003cspan style=\"color:#50fa7b\"\u003eget\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;migre\u0026#34;\u003c/span\u003e));\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Encurtando links em Java usando o Migre.me"},{"content":"Gerenciar recursos sempre foi algo muito chato, principalmente quando parte do ciclo de vida do objeto é fecha-lo, senão você poderá ter problemas na execução do seu programa. Vamos por exemplo analisar um código que abre um arquivo e itera sobre ele exibindo seu conteúdo linha a linha:\nFileReader readerAntigo = null; try { readerAntigo = new FileReader(\u0026#34;arquivo.txt\u0026#34;); Scanner scanner = new Scanner(readerAntigo); while(scanner.hasNext()) { System.out.println(scanner.next()); } } catch (FileNotFoundException e ) { System.out.println(\u0026#34;Arquivo não encontrado\u0026#34;); } finally { try { readerAntigo.close(); } catch (IOException e) { System.out.println(\u0026#34;Erro ao fechar o arquivo\u0026#34;); } } Perceba como é chato gerenciar o arquivo, para que eu possa abrir e fechar são necessário duas capturas de sessão, sem contar que ainda é necessário que o programador lembre-se de fechar o arquivo, algo que não pode ser tão crítico, mas se imaginarmos conexões JDBC, logo o banco começará a recusar conexões pois esquecemos de fecha-las anteriormente.\nPara ajudar a solucionar isso, no Java 7 foi introduzi o AutoCloseable, que permite que recursos existam apenas dentro de um bloco e ao seu final (ou caso seja lançado uma exceção) sejam fechados devidamente. Para isso, foi criada a interface AutoCloseable, e o a classe que a implementada de sobrescrever o método close().Ao abrir um novo recurso, você deve declara-lo e instancia-lo dentro de parentes após o try, ficando assim:\ntry (ClasseAutoCloseable objeto = new ClasseAutoCloseable(...)) { //Dentro deste escopo o objeto existirá //ao final será chamado o método close() da interface AutoCloseable } catch (Exception e ) { //Caso tenha uma exception, também será dado o close() } Desta forma podemos eliminar em muito os blocos finally\u0026rsquo;s que existem apenas para fechar recursos abertos, pois agora ele será fechado automaticamente.\nNosso exemplo acima, que abre e exibe o arquivo, ficando bem inferior a quantidade de linhas e mais simples de ler:\ntry(FileReader reader = new FileReader(\u0026#34;arquivo.txt\u0026#34;)) { Scanner scanner2 = new Scanner(reader); scanner2.forEachRemaining(System.out::println); //Esse recurso surgiu no Java 8! } catch(IOException e) { System.out.println(\u0026#34;Erro ao fechar o arquivo\u0026#34;); } Essa abordagem já esta usada em linguagens como C#, e agora o Java também possui este recurso que facilita em muito a vida do desenvolvedor.\n","permalink":"https://blog.lucaspolo.dev/posts/dando-um-close-no-java-7-autocloseable/","summary":"\u003cp\u003eGerenciar recursos sempre foi algo muito chato, principalmente quando parte do ciclo de vida do objeto é fecha-lo, senão você poderá ter problemas na execução do seu programa. Vamos por exemplo analisar um código que abre um arquivo e itera sobre ele exibindo seu conteúdo linha a linha:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eFileReader readerAntigo \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enull\u003c/span\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003etry\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    readerAntigo \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e FileReader(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;arquivo.txt\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    Scanner scanner \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e Scanner(readerAntigo);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003ewhile\u003c/span\u003e(scanner.\u003cspan style=\"color:#50fa7b\"\u003ehasNext\u003c/span\u003e()) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(scanner.\u003cspan style=\"color:#50fa7b\"\u003enext\u003c/span\u003e());\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} \u003cspan style=\"color:#ff79c6\"\u003ecatch\u003c/span\u003e (FileNotFoundException e ) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Arquivo não encontrado\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e} \u003cspan style=\"color:#ff79c6\"\u003efinally\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003etry\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        readerAntigo.\u003cspan style=\"color:#50fa7b\"\u003eclose\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    } \u003cspan style=\"color:#ff79c6\"\u003ecatch\u003c/span\u003e (IOException e) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Erro ao fechar o arquivo\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePerceba como é chato gerenciar o arquivo, para que eu possa abrir e fechar são necessário duas capturas de sessão, sem contar que ainda é necessário que o programador lembre-se de fechar o arquivo, algo que não pode ser tão crítico, mas se imaginarmos conexões JDBC, logo o banco começará a recusar conexões pois esquecemos de fecha-las anteriormente.\u003c/p\u003e","title":"Dando um close no Java 7: AutoCloseable"},{"content":"As vezes precisamos processar dados em um volume maior, onde é necessário filtrar a informação, selecionar ou alterar o que queremos para depois realizar o processamento. Como exemplo, vamos imaginar uma lista de alunos, onde cada instância tem seu nome e nota. Desta lista queremos a média geral, a média dos alunos aprovados (ou seja, quem tirou nota seis ou mais) e a média dos reprovados (nota menor que seis). Para isso, vamos primeiro visualizar nossa lista:\nList\u0026lt;Aluno\u0026gt; alunos = new ArrayList\u0026lt;\u0026gt;(); Aluno aluno1 = new Aluno(\u0026#34;Cebolinha\u0026#34;, 8.0); Aluno aluno2 = new Aluno(\u0026#34;Cascao\u0026#34;, 6.5); Aluno aluno3 = new Aluno(\u0026#34;Monica\u0026#34;, 9.0); Aluno aluno4 = new Aluno(\u0026#34;Magali\u0026#34;, 3.0); alunos.addAll(Arrays.asList(aluno1, aluno2, aluno3, aluno4)); Apesar da simplicidade dos nossos dados, para poder separar a nossa lista de forma a realizar esta média, precisamos iterar sobre todos os seus elementos. Vamos fazer primeiro a média mais simples, sem nenhum critério:\nDouble media = new Double(\u0026#34;0\u0026#34;); int quantidadeDeAlunos = 0; for (Aluno aluno : alunos) { media = Double.sum(media, aluno.getNota()); quantidadeDeAlunos++; } System.out.println(media / quantidadeDeAlunos); Repare no trabalho de declarar a variável e iterar sobre todos os seus elementos, ainda de maneira simples, pois ainda não temos nenhuma regra implementada, vamos agora colocar os outros dois trechos de código, implementando a média dos aprovados e reprovados:\nmedia = new Double(\u0026#34;0\u0026#34;); quantidadeDeAlunos = 0; for (Aluno aluno : alunos) { if (aluno.getNota() \u0026gt;= 6) { media = Double.sum(media, aluno.getNota()); quantidadeDeAlunos++; } } System.out.println(media / quantidadeDeAlunos); media = new Double(\u0026#34;0\u0026#34;); quantidadeDeAlunos = 0; for (Aluno aluno : alunos) { if (aluno.getNota() \u0026lt; 6) { media = Double.sum(media, aluno.getNota()); quantidadeDeAlunos++; } } System.out.println(media / quantidadeDeAlunos); Da mesma forma que meu modem toda vez que a internet cai, precisei reiniciar as variáveis de média e rescrever os for\u0026rsquo;s, mas eu sei que é possível fazer em apenas uma iteração, desta forma podemos economizar tempo, vamos tentar ver a versão reduzida deste código:\nDouble mediaAprovados = new Double(\u0026#34;0\u0026#34;); Double mediaReprovados = new Double(\u0026#34;0\u0026#34;); int quantidadeDeAlunosAprovados = 0; int quantidadeDeAlunosReprovados = 0; for (Aluno aluno : alunos) { if(aluno.getNota() \u0026gt;= 6) { mediaAprovados = Double.sum(mediaAprovados, aluno.getNota()); quantidadeDeAlunosAprovados++; } else { mediaReprovados = Double.sum(mediaReprovados, aluno.getNota()); quantidadeDeAlunosReprovados++; } } System.out.println( (Double.sum(mediaAprovados, mediaReprovados)) / (quantidadeDeAlunosAprovados + quantidadeDeAlunosReprovados)); System.out.println(mediaAprovados / quantidadeDeAlunosAprovados); System.out.println(mediaReprovados / quantidadeDeAlunosReprovados); } Nesta versão, conseguimos reduzir bem o nosso código, centralizando tudo em um único foreach, porém o gerenciamento manual aumentou, pois tivemos que criar novas variáveis e ainda realizar o cálculo das médias dentro das chamadas das funções de saída.\nAbstraindo a função do código, chegamos a algumas conclusões que podemos traduzir melhor, a primeira coisa que fazemos é filtrar com os requisitos que queremos, ou seja, as notas, depois de filtrar as entidades Aluno, devemos selecionar qual informação vamos processar (se necessário trata-la) e depois realizamos a agregação dessa informação, somando tudo em uma variável double (por exemplo, mediaAprovados).\nNo artigo passado, vimos como realizar a primeira tarefa utilizando o Java 8, onde aprendemos sobre os filtros, porém ainda precisamos realizar algumas outras operações, que é selecionar a informação que queremos (mapear) e depois agrega-la (reduzir). Para nossa sorte, a nova versão do Java também possui este tratamento, onde podemos trabalhar com métodos como map()(e suas variações) e reduce(), todas elas da classe Stream. Abaixo vemos o primeiro exemplo, da média geral:\nDouble media = alunos.stream() .filter(a -\u0026gt; a.getNota() \u0026gt;= 0) //Filtrando o resultado .mapToDouble(aluno -\u0026gt; { return aluno.getNota(); } ) //mapeando para uma DoubleStream as notas .average().getAsDouble(); //Pegando a média e retornando o double System.out.println(media); Chega a ser covarde a abordagem, todas as iterações estão encapsuladas e tudo é resolvido em apenas em uma linha, com uma sintaxe bem mais limpa, além de termos fornecidos métodos que realizam operações matemáticas, como average(), facilitando toda a operação. Agora vejamos como são todas as implementações, pegando a média dos aprovados e reprovados:\nDouble media= alunos.stream() .filter(a -\u0026gt; a.getNota() \u0026gt;= 0) .mapToDouble(aluno -\u0026gt; { return aluno.getNota(); } ) .average().getAsDouble(); System.out.println(media); Double mediaAprovados = alunos.stream() .filter(a -\u0026gt; a.getNota() \u0026gt;= 6) .mapToDouble(aluno -\u0026gt; { return aluno.getNota(); } ) .average().getAsDouble(); System.out.println(mediaAprovados); Double mediaReprovados = alunos.stream() .filter(a -\u0026gt; a.getNota() \u0026lt; 6) .mapToDouble(aluno -\u0026gt; { return aluno.getNota(); } ) .average().getAsDouble(); System.out.println(mediaReprovados); Vemos que a legibilidade do código aumenta, mas repare que os três códigos são iguais, mudando apenas o filtro, e como repetição de código é mais feio que jogar cachorro na estrada, vamos pensar numa maneira mais bonita de lidar com o código. Lembre-se que as expressões lambda, como o nosso filtro, são na verdade implementações dinâmicas da classe Filter, então podemos receber ela como parâmetro. Vamos criar um método para lidar com esse parâmetro, recebendo a lista de alunos e o filtro, retornando a sua média:\npublic static Double media(List\u0026lt;Aluno\u0026gt; alunos, Predicate\u0026lt;Aluno\u0026gt; filtro) { return alunos.stream() .filter(filtro) .mapToDouble(aluno -\u0026gt; { return aluno.getNota(); } ) .average().getAsDouble(); } Agora que temos os métodos podemos substituir o código por chamadas as funções, mas lembre-se que não é necessário criar classes anônimas, afinal as expressões lambda são convertidas automaticamente pelamáquina virtual em implementações da interface:\nDouble media = media( alunos, a-\u0026gt; a.getNota() \u0026gt; 0 ); System.out.println(media); Double mediaAprovados = media(alunos, a -\u0026gt; a.getNota() \u0026gt;= 6 ); System.out.println(mediaAprovados); Double mediaReprovados = media(alunos, a -\u0026gt; a.getNota() \u0026lt; 6 ); System.out.println(mediaReprovados); Repare como a nossa classe ficou muito mais simples, com um código simples de se compreender e dar manutenção, podendo ampliar facilmente a função. Fica muito simples processar informações desta forma, onde podemos não apenas selecionar as informações e reduzi-la, mas podemos transforma-la antes. Poderíamos converter para String\u0026rsquo;s todas as notas e concatena-las, ou mais mil e uma funções. Isso é inclusive a princípio de alguns banco de dados para processamento de grandes massas de dados, como o Hadoop, onde estas informações são utilizadas para análises de Business Inteligence e em sistemas de apoio a decisão.\n","permalink":"https://blog.lucaspolo.dev/posts/mapeando-e-reduzindo-java-8/","summary":"\u003cp\u003eAs vezes precisamos processar dados em um volume maior, onde é necessário filtrar a informação, selecionar ou alterar o que queremos para depois realizar o processamento. Como exemplo, vamos imaginar uma lista de alunos, onde cada instância tem seu nome e nota. Desta lista queremos a média geral, a média dos alunos aprovados (ou seja, quem tirou nota seis ou mais) e a média dos reprovados (nota menor que seis). Para isso, vamos primeiro visualizar nossa lista:\u003c/p\u003e","title":"Mapeando e Reduzindo - Java 8"},{"content":"Muitas vezes precisamos filtrar listas, listas de todos os tipos, desde números básicos, passando por Strings, até tipos complexos. Abaixo temos um exemplo simples disto, onde temos uma lista com alguns nomes e queremos filtra-la e exibi-la para o usuário (no caso, todos os nomes que tiverem a letra \u0026ldquo;u\u0026rdquo; serão exibidos):\nList\u0026lt;String\u0026gt; nomes = new ArrayList\u0026lt;\u0026gt;(); nomes.add(\u0026#34;João da Silva\u0026#34;); nomes.add(\u0026#34;Joaquim da Padaria\u0026#34;); nomes.add(\u0026#34;Lucas Polo\u0026#34;); nomes.add(\u0026#34;Chaves\u0026#34;); List\u0026lt;String\u0026gt; nomesFiltrados = new ArrayList\u0026lt;\u0026gt;(); System.out.println(\u0026#34;Iniciando filtragem\u0026#34;); for (String nome : nomes) { System.out.println(\u0026#34;Avaliando: \u0026#34; + nome); if (nome.contains(\u0026#34;u\u0026#34;)) nomesFiltrados.add(nome); } System.out.println(\u0026#34;Iniciando impressão\u0026#34;); for (String nome : nomesFiltrados) { System.out.println(nome); } A saida é: Iniciando filtragem Avaliando: João da Silva Avaliando: Joaquim da Padaria Avaliando: Lucas Polo Avaliando: Chaves Iniciando impressão Joaquim da Padaria Lucas Polo Repare que primeiros os resultados são filtrados e depois exibidos, mas variando com o tamanho da lista, pode demorar muito tempo para filtrarmos uma lista inteira, e por isso, muitas vezes, é melhor avaliar se o elemento passa no filtro e trata-lo devidamente, ganhando assim mais velocidade. Na programação funcional, temos um meio de lidar com isso, chamado avaliação preguiçosa.\nLembrando que métodos também pode ser passados como parâmetros, por isso, podemos armazena-los e utilizar suas funções posteriormente. Métodos que realizam a avaliação de elementos, são conhecidos como predicados, que no Java é representado pela classe Predicate e contem o método filter.\nEstes métodos recebem um parâmetro, avaliam se o mesmo é válido e caso sim, retorna verdadeiro. Para poder iterar sobre todos os elementos de uma coleção desta forma, precisamos converte-la em um fluxo de dados, que basicamente é feita utilizando o método stream():\nSystem.out.println(\u0026#34;Iniciando filtragem\u0026#34;); Stream\u0026lt;String\u0026gt; streamComFiltro = nomes.stream().filter(new Predicate\u0026lt;String\u0026gt;() { @Override public boolean test(String nome) { System.out.println(\u0026#34;Avaliando: \u0026#34; + nome); return nome.contains(\u0026#34;u\u0026#34;); } }); System.out.println(\u0026#34;Iniciando impressão\u0026#34;); streamComFiltro.forEach(System.out::println); Saida: Iniciando filtragem Iniciando impressão Avaliando: João da Silva Avaliando: Joaquim da Padaria Joaquim da Padaria Avaliando: Lucas Polo Lucas Polo Avaliando: Chaves Agora a parte mais importante, mesmo chamando o método filter() ele ainda não fez a execução do filtro, apenas quando pedimos o resultado no método foreach() é que inicia a avaliação preguiçosa, chamando conforme a necessidade.\nAlém disso, podemos criar métodos em tempo de execução, por isso o uso de classes anônimas não se torna mais necessário, podemos criar então o método diretamente como parâmetro, utilizando o operador -\u0026gt;, desta forma, ficando desse jeito:\nSystem.out.println(\u0026#34;Iniciando filtragem\u0026#34;); streamComFiltro = nomes.stream().filter(nome -\u0026gt; { System.out.println(\u0026#34;Avaliando: \u0026#34; + nome); return nome.contains(\u0026#34;u\u0026#34;); }); System.out.println(\u0026#34;Iniciando impressão\u0026#34;); streamComFiltro.forEach(System.out::println); Repare que desta forma, fica muito mais simples lidar com filtragens via código, deixando o código mais limpo. Mas como você pode reparar, o método stream() retorna diretamente uma Stream e depois o filter() também retorna uma Stream, então podemos resumir nosso código em uma linha (agora sem as saídas de textos informativas):\nnomes.stream() .filter(nome -\u0026gt; {return nome.contains(\u0026#34;u\u0026#34;);}) .forEach(System.out::println); Repare que conseguimos reduzir um código de 6 linhas para uma única, deixando muito mais simples e claro. Ainda temos coisas muito mais poderosas vindo com o Java 8, como o map e reduce que permite filtrar e já processar os dados unificando eles (por exemplo, somando todos os números primos de 1 a 100). Iremos abordar essas novas funcionalidades em um próximo post.\n","permalink":"https://blog.lucaspolo.dev/posts/filtrando-resultados-predicados-java-8/","summary":"\u003cp\u003eMuitas vezes precisamos filtrar listas, listas de todos os tipos, desde números básicos, passando por Strings, até tipos complexos. Abaixo temos um exemplo simples disto, onde temos uma lista com alguns nomes e queremos filtra-la e exibi-la para o usuário (no caso, todos os nomes que tiverem a letra \u0026ldquo;u\u0026rdquo; serão exibidos):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eList\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eString\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e nomes \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e ArrayList\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u0026gt;\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enomes.\u003cspan style=\"color:#50fa7b\"\u003eadd\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;João da Silva\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enomes.\u003cspan style=\"color:#50fa7b\"\u003eadd\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Joaquim da Padaria\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enomes.\u003cspan style=\"color:#50fa7b\"\u003eadd\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Lucas Polo\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003enomes.\u003cspan style=\"color:#50fa7b\"\u003eadd\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Chaves\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eList\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u003c/span\u003eString\u003cspan style=\"color:#ff79c6\"\u003e\u0026gt;\u003c/span\u003e nomesFiltrados \u003cspan style=\"color:#ff79c6\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003enew\u003c/span\u003e ArrayList\u003cspan style=\"color:#ff79c6\"\u003e\u0026lt;\u0026gt;\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSystem.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Iniciando filtragem\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e (String nome : nomes) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Avaliando: \u0026#34;\u003c/span\u003e \u003cspan style=\"color:#ff79c6\"\u003e+\u003c/span\u003e nome);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#ff79c6\"\u003eif\u003c/span\u003e (nome.\u003cspan style=\"color:#50fa7b\"\u003econtains\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;u\u0026#34;\u003c/span\u003e)) nomesFiltrados.\u003cspan style=\"color:#50fa7b\"\u003eadd\u003c/span\u003e(nome);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSystem.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(\u003cspan style=\"color:#f1fa8c\"\u003e\u0026#34;Iniciando impressão\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#ff79c6\"\u003efor\u003c/span\u003e (String nome : nomesFiltrados) {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    System.\u003cspan style=\"color:#50fa7b\"\u003eout\u003c/span\u003e.\u003cspan style=\"color:#50fa7b\"\u003eprintln\u003c/span\u003e(nome);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eA saida é:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIniciando filtragem\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eAvaliando: João da Silva\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eAvaliando: Joaquim da Padaria\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eAvaliando: Lucas Polo\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eAvaliando: Chaves\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eIniciando impressão\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eJoaquim da Padaria\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLucas Polo\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRepare que primeiros os resultados são filtrados e depois exibidos, mas variando com o tamanho da lista, pode demorar muito tempo para filtrarmos uma lista inteira, e por isso, muitas vezes, é melhor avaliar se o elemento passa no filtro e trata-lo devidamente, ganhando assim mais velocidade. Na programação funcional, temos um meio de lidar com isso, chamado avaliação preguiçosa.\u003c/p\u003e","title":"Filtrando resultados (Predicados) - Java 8"},{"content":"Quando comecei a programar na escola (curso técnico que fiz na época), comecei em uma das linguagens mais legais e, de certo modo, estranha que existe, a linguagem C. Alguns conceitos dela não são claros logo de inicio, pois não fazem nenhum paralelo com o mundo real. Um deles é o conceito de ponteiros e alocação de memória, onde você dinamicamente pode alocar memória para seu programa utilizar. Porém, como dizia o Tio Ben: \u0026ldquo;Grandes poderes trazem grandes responsabilidades\u0026rdquo;, logo você se via obrigado a \u0026ldquo;lembrar\u0026rdquo; de liberar toda a memória alocada quando não fizesse mais uso dela, senão seu programa logo travaria junto com o seu sistema operacional.\nO mundo mudou, os tempos agora são outros, temos a internet, o relógio digital e o Garbage Collector, que faz toda a gerência da coleta de memória que não é mais utilizada por nossos objetos. Porém agora temos que gerênciar outros recursos, como objetos que abrem arquivos e devem fecha-los ou conexões com o banco de dados. Caso você não os feche, seu arquivo não poderá ser aberto novamente ou seu banco de dados começará a recusar conexões, e sinceramente, isso é muito chato.\nPor isso, vamos lembrar de fechar todas as nossas conexões nos nossos DAOs:\npublic class CarroDao { private Connection connection; private String INSERIR_CARRO = \u0026#34;INSERT INTO carros(nome, marca) VALUES(?, ? )\u0026#34;; private String EXCLUIR_CARRO = \u0026#34;DELETE FROM carros WHERE id = ?\u0026#34;; private String RECUPERAR_CARRO = \u0026#34;SELECT id, nome, marca FROM carros WHERE id = ?\u0026#34;; public CarroDao() { connection = ConnectionFactory.getConnection(); } public void inserir(Carro carro) {...} public void excluir(int id) {...} public void recuperar(int id) {...} private void fecharRecursos(ResultSet rs, PreparedStatement ps) {...} public void fechaConexao() { try { connection.close(); } catch(SQLException e) { System.err.println(\u0026#34;Problemas ao fechar a conexao: \u0026#34; + e.getMessage()); } } } O nosso código principal, que faz uso da classe CarroDao:\npublic class AppMain { public static void main(String[] args) { Carro carro = new Carro(); carro.setNome(\u0026#34;Time Machine\u0026#34;); carro.setMarca(\u0026#34;DeLorean\u0026#34;); CarroDao carroDao = new CarroDao(); carroDao.inserir(carro); carroDao.fechaConexao(); } } Até este momento, não teremos problemas, porém podemos agora tentar utilizar novamente o carroDaoe realizar alguma outra operação:\npublic class AppMain { public static void main(String[] args) { //...Codigo anterior //Outra operação carroDao.excluir(1); carroDao.fechaConexao(); } } E funciona normalmente, mas se mantivermos esse padrão e criarmos outro Dao, por exemplo, PessoaDao, que também instanciará uma Connection para ela e também possuirá o método fecharConexao, que também devemos lembrar de fechar:\npublic class AppMain { public static void main(String[] args) { //...Codigo anterior //Outra operação carroDao.excluir(1); carroDao.fechaConexao(); Pessoa pessoa = new Pessoa(\u0026#34;Marty McFly\u0026#34;); PessoaDao pessoaDao = new PessoaDao(); pessoaDao.inserir(pessoa); pessoaDao.fecharConexao(); } } Perceba que até o momento criamos dois DAOs e também duas conexões com o banco de dados, cada DAO contendo a sua conexão, porém como é de boa prática, não devemos criar conexões indiscriminadamente com o banco, sendo a melhor solucão usar um pool de conexões e também caso as operações estejam em um mesmo contexto, utilizar a mesma conexão para realizar todas as operações e no final, fechar ela.\nPorém como podemos fazer isso de maneira limpa e simples? Poderiamos dar um getConnection do CarroDao e recuperar a conexão dele e usar para PessoaDao também, mas e se usarmos o PessoaDao sem querermos utilizar o CarroDao, o que faremos? O termo DAO vem de Data Access Object, sendo utilizado para realizar a recuperação dos dados e a conversão em objetos, deixando claro que não é de sua responsabilidade criar conexões e acessar os recursos.\nDe maneira mais limpa, podemos simplesmente alterar os nossos DAOs para receberem a conexão dos seus clientes, deixando a cargo deles a criação e manutenção da conexão com o banco. Porém os DAOs precisam obrigatoriamente receber a conexão, por isso vamos colocar Connection como parâmetro do construtor dos DAOs e podemos remover os métodos fecharConexao:\npublic class CarroDao { private Connection connection; public CarroDao(Connection connection) { this.connection = connection; } //...metodos de manipução já existentes, e removido o método fecharConexao } Nossa classe CarroDao agora está bem mais coerente com o seu papel, agora devemos criar a conexão dentro do código cliente, utilizando ela onde for necessário:\npublic class AppMain { public static void main(String[] args) { Carro carro = new Carro(); carro.setNome(\u0026#34;Time Machine\u0026#34;); carro.setMarca(\u0026#34;DeLorean\u0026#34;); Connection connection = ConnectionFactory.getConnection(); CarroDao carroDao = new CarroDao(connection); carroDao.inserir(carro); carroDao.excluir(1); Pessoa pessoa = new Pessoa(\u0026#34;Marty McFly\u0026#34;); PessoaDao pessoaDao = new PessoaDao(connection); pessoaDao.inserir(pessoa); try { connection.close(); } catch(SQLException e) { System.err.println(\u0026#34;Problemas ao fechar a conexao: \u0026#34; + e.getMessage()); } } } Com apenas uma conexão conseguimos realizar todas as nossas operações, e facilmente também podemos transacionar a nossa operação, caso ocorra algum problema, realizamos o rollback de todas as operações anteriores que utilizaram a mesma conexão e devido a isto estão no mesmo contexto.\nO nome deste padrão de desenvolvimento é Inversão de Controle, onde você repassa o gerenciamento de recursos um nível acima e recuperando os mesmos onde for necessário através de injeção de dependência (que no nosso caso, obrigamos a passar pelo construtor).\nA inversão de controle e a injeção de dependências (em inglês, Inversion of Control - IoC, e Dependency Injection - DI, respectivamente), além de permitirem que tenhamos classes com menos responsabilidades e o mais interessante, que possamos gerenciar facilmente objetos que acessam recursos externos. No nosso caso, a conexão estava sendo gerenciada direto pela aplicação exemplo (AppMain), porém podemos facilmente deixar a cargo de algum framework ou container de aplicação este gerenciamento, e nuances como o local do banco de dados, usuários e senhas, serem facilmente configuradas por XMLs ou annotations.\nNo futuro teremos um artigo mostrando como usar a injeção de depedências com o framework mais conhecido para esta tarefa, o Spring, mostrando sua configuração básica e modo de operação.\n","permalink":"https://blog.lucaspolo.dev/posts/inversao-de-controle-e-injecao-de-dependencias/","summary":"\u003cp\u003eQuando comecei a programar na escola (curso técnico que fiz na época), comecei em uma das linguagens mais legais e, de certo modo, estranha que existe, a linguagem C. Alguns conceitos dela não são claros logo de inicio, pois não fazem nenhum paralelo com o mundo real. Um deles é o conceito de ponteiros e alocação de memória, onde você dinamicamente pode alocar memória para seu programa utilizar. Porém, como dizia o Tio Ben: \u0026ldquo;Grandes poderes trazem grandes responsabilidades\u0026rdquo;, logo você se via obrigado a \u0026ldquo;lembrar\u0026rdquo; de liberar toda a memória alocada quando não fizesse mais uso dela, senão seu programa logo travaria junto com o seu sistema operacional.\u003c/p\u003e","title":"Inversão de Controle e Injeção de Dependências"},{"content":"O Java 8 que será lançado em breve e já possui versões de teste disponíveis para download tem uma novidade interessante, que é tratar métodos como objetos (criando assim o suporte a funções Lambda). Uma vez que métodos podem ser tratados como objetos, você pode passa-los como parâmetro ou cria-los em tempo de execução.\nVamos dissecar mais sobre essas novidades no decorrer do tempo, mas por enquanto vamos ver um exemplo do que podemos fazer. Antigamente, para ler um arquivo e imprimir o seu conteúdo linha a linha poderíamos fazer algo assim:\npublic class LeitorDeArquivo { public static void main(String[] args) { try(Scanner scanner = new Scanner(new FileInputStream(\u0026#34;/Users/lucaspolo/teste\u0026#34;))) { while(scanner.hasNext()) { System.out.println(scanner.next()); } } catch (FileNotFoundException ex) { System.err.println(\u0026#34;Problemas ao abrir e ler arquivo: \u0026#34; + ex.getMessage()); } } Basicamente estamos dizendo o seguinte enquanto houver um próximo elemento, imprima este próximo elemento. No Java 8 podemos deixar menor ainda este trecho de código, invertendo a maneira como lidamos com este tipo de instrução, agora podemos dizer para os elementos seguintes, faça a seguinte operação, conforme o código abaixo, que possui o mesmo funcionamento:\npublic class LeitorDeArquivo { public static void main(String[] args) { try(Scanner scanner = new Scanner(new FileInputStream(\u0026#34;/Users/lucaspolo/teste\u0026#34;))) { scanner.forEachRemaining(System.out::println); } catch (FileNotFoundException ex) { System.err.println(\u0026#34;Problemas ao abrir e ler arquivo: \u0026#34; + ex.getMessage()); } } Repare que estamos passando o método println do objeto out da classe estática System como parâmetro. Perceba que o operador :: é responsável por esse passagem da referência do (a partir do Java 8) objeto println.\nO segredo ocorre no tratamento desse parâmetro recebido, ele converte em uma interface e injeta o seu objeto que no caso é uma String. No futuro veremos qual interface é essa e seu funcionamento por dentro.\n","permalink":"https://blog.lucaspolo.dev/posts/metodos-como-parametros-java-8/","summary":"\u003cp\u003eO Java 8 que será lançado em breve e já possui versões de teste disponíveis para download tem uma novidade interessante, que é tratar métodos como objetos (criando assim o suporte a funções Lambda). Uma vez que métodos podem ser tratados como objetos, você pode passa-los como parâmetro ou cria-los em tempo de execução.\u003c/p\u003e\n\u003cp\u003eVamos dissecar mais sobre essas novidades no decorrer do tempo, mas por enquanto vamos ver um exemplo do que podemos fazer. Antigamente, para ler um arquivo e imprimir o seu conteúdo linha a linha poderíamos fazer algo assim:\u003c/p\u003e","title":"Métodos como parâmetros - Java 8"},{"content":"Existe uma lei que rege todos os lugares do mundo, em todos os planos e dimensões. Esta lei é a Lei de Murphy, dizendo que você pode morrer e virar um superpolicial robô chamado Robocop. Brincadeiras a parte, a Lei de Murphy diz basicamente que se algo pode dar errado, isto irá dar errado, ou seja, você não deve deixar nenhuma fresta onde o erro pode ocorrer. O seu criador, Edward A. Murphy, um engenheiro aeroespacial, dizia que nunca devemos deixar uma brecha no projeto, pois será neste ponto onde ocorrerá a falha, e como muitas outras coisas que vieram do mundo da engenharia para a informática, esta lei também veio para o nosso ambiente.\nMuitos dos erros que ocorrem em sistemas orientados a objetos são causados por simplesmente a facilidade em inserir parâmetros incorretos ou ter acesso a parâmetros que não deveriam ser expostos de qualquer maneira, sem antes passar por algum tratamento ou algoritmo.\nPor exemplo, observe a classe abaixo e tente observar quais erros podem ocorrer:\npublic class SeparadorDeAlunosPorNota { private List\u0026lt;Aluno\u0026gt; alunosAprovados = new ArrayList\u0026lt;\u0026gt;(); private List\u0026lt;Aluno\u0026gt; alunosReprovados = new ArrayList\u0026lt;\u0026gt;(); public void adicionaAluno(Aluno aluno, float nota) { if (nota \u0026gt; 6) { alunosAprovados.add(aluno); } else { alunosReprovados.add(aluno); } } public List\u0026lt;Aluno\u0026gt; getAlunosAprovados() { return alunosAprovados; } public List\u0026lt;Aluno\u0026gt; getAlunosReprovados() { return alunosReprovados; } } Como vocês podem ver, essa classe segue alguns princípios básicos de encapsulamento, onde seu atributos são todos privados e o acesso é feito apenas através de métodos. Porém, observando com um pouco de cuidado, podemos notar que não é bem isso que ocorre, observe abaixo um exemplo de utilização da classe acima:\npublic class MinhaAplicacaoEscolarMain { public static void main(String args[]) { SeparadorDeAlunosPorNota separador = new SeparadorDeAlunosPorNota(); Aluno aluno1 = new Aluno(\u0026#34;Magali\u0026#34;); Aluno aluno2 = new Aluno(\u0026#34;Cascao\u0026#34;); Aluno aluno3 = new Aluno(\u0026#34;Monica\u0026#34;); separador.adicionaAluno(aluno1, 7.0); separador.adicionaAluno(aluno2, 4.5); separador.adicionaAluno(aluno3, 9.5); List\u0026lt;Aluno\u0026gt; alunosAprovados = separador.getAlunosAprovados(); List\u0026lt;Aluno\u0026gt; alunosReprovados = separador.getAlunosReprovados(); System.out.println(\u0026#34;Lista de alunos reprovados: \u0026#34;); for (Aluno aluno : alunosReprovados) { System.out.println(aluno.getNome()); } System.out.println(\u0026#34;Lista de alunos aprovados: \u0026#34;); for (Aluno aluno : alunosAprovados) { System.out.println(aluno.getNome()); } //Até aqui tudo bem, mas se atente ao que ocorre abaixo alunosAprovados.add(new Aluno(\u0026#34;Cebolinha\u0026#34;)); //Agora recuperando novamente a lista de alunos aprovados alunosAprovados = separador.getAlunosAprovados(); //Imprimindo mais uma vez os alunos aprovados System.out.println(\u0026#34;Lista de alunos aprovados: \u0026#34;); for (Aluno aluno : alunosAprovados) { System.out.println(aluno.getNome()); } //Imprimiu o Cebolinha, que entrou na lista mesmo sem passar por uma avaliação //Desta vez o plano infalível dele funcionou } } Saida:\nLista de alunos reprovados: Cascao Lista de alunos aprovados: Magali Monica Lista de alunos aprovados: Magali Monica Cebolinha O erro ocorre ao solicitar novamente a lista de alunos aprovados, temos agora um novo aluno, porém que não passou pela avaliação do método adicionaAluno, causando um pequeno transtorno. No contexto desta pequena aplicação já podemos ver que é um erro muito visível, porém pode ser muito pior em uma aplicação distribuída e/ou acessada por diversos clientes ao mesmo tempo, por exemplo, um website.\nApesar de todas as preocupações com a visibilidade dos campos, deixamos passar um meio de acessar diretamente um dos atributos, através de sua referência em memória. O método getAlunosAprovados devolve esta referência quando é invocando, deixando exposto uma parte do nosso objeto. Para tratar este problema, bastaria realizar uma alteração simples, criando uma cópia da lista e devolvendo para o cliente, conforme abaixo:\npublic class SeparadorDeAlunosPorNota { //...métodos e atributos anteriores public List\u0026lt;Aluno\u0026gt; getAlunosAprovados() { return new ArrayList\u0026lt;\u0026gt;(alunosAprovados); //Utilizando o construtor de cópia de ArrayList } public List\u0026lt;Aluno\u0026gt; getAlunosReprovados() { return new ArrayList\u0026lt;\u0026gt;(alunosReprovados); } } E a saida agora é:\nCascao Lista de alunos aprovados: Magali Monica Lista de alunos aprovados: Magali Monica Este exemplo mostra como o encapsulamento vai muito além dos modificadores de acesso. Precisamos claramente, deixar encapsulado também todas as referências aos atributos internos, não adiantando criar métodos que apenas repassem as referências internas dos objetos. Apenas em uma situação realizar esta ação não prejudicará o estado do seu objeto, quando o atributo é final e o objeto é imutável, pois desta forma não há como alterar o objeto referenciado, como no exemplo abaixo:\npublic class Aluno { private final String nome; Aluno(String nome) { this.nome = nome; } public String getNome() { return this.nome; } } Da forma como está em cima, o atributo nome poderia até ser publico e mesmo assim não seria possível alterar o seu valor, pois a classe String é imutável e nenhum de seus métodos alterar o seu estado, o que não é o caso, por exemplo, da classe StringBuffer, que faz o contraponto através de seu método append por questões de desempenho.\nComo você viu acima, classes imutáveis auxiliam no encapsulamento dos nossos objetos, pois como o estado do objeto não se altera, não existe como inserir informações inconsistentes dentro do objeto, sendo que o máximo que pode ocorrer é a criação de um novo objeto com um estado não coerente. No próximo post vamos falar um pouco mais sobre estes objetos, como construir as suas classes e quais os benefícios.\n","permalink":"https://blog.lucaspolo.dev/posts/desconstruindo-a-orientacao-a-objetos-encapsulando-de-verdade-os-seus-atributos/","summary":"\u003cp\u003eExiste uma lei que rege todos os lugares do mundo, em todos os planos e dimensões. Esta lei é a Lei de Murphy, dizendo que você pode morrer e virar um superpolicial robô chamado Robocop. Brincadeiras a parte, a Lei de Murphy diz basicamente que se algo pode dar errado, isto irá dar errado, ou seja, você não deve deixar nenhuma fresta onde o erro pode ocorrer. O seu criador, Edward A. Murphy, um engenheiro aeroespacial, dizia que nunca devemos deixar uma brecha no projeto, pois será neste ponto onde ocorrerá a falha, e como muitas outras coisas que vieram do mundo da engenharia para a informática, esta lei também veio para o nosso ambiente.\u003c/p\u003e","title":"Desconstruindo a orientação a objetos: Encapsulando de verdade os seus atributos"},{"content":"Lembro-me como se fosse ontem (que poético isso) a primeira vez que eu ouvi sobre a orientação a objetos. Depois de muito tempo lidando com linguagens puramente procedurais (C, COBOL, Visual Basic), eu ouvi falar sobre esse novo paradigma e é claro, sobre uma das linguagens que usa ele, o Java. A primeira coisa que eu ouvi foi \u0026ldquo;a orientação a objetos é ótima para construir interfaces gráficas\u0026rdquo;, e eu sei, que se você tem o mínimo de noção sobre o que é orientação a objetos, sabe que isso foi uma enorme canelada*.\nJá na faculdade, eu tive aulas de orientação a objetos, iniciando com C++ e no final, em Java. Eu já tinha estudado por conta um pouco sobre orientação a objetos e vi como destacavam os mecanismos de herança, e até hoje muitas literaturas ainda dão a maior ênfase na herança. Porém uma aula que me fez ver como a orientação a objetos é poderosa foi sobre o polimorfismo e a capacidade de chamar métodos de maneira dinâmica durante a execução. E é claro, para não dizer que não falei das flores, aprendemos sobre o encapsulamento, o que era basicamente usar private no que queria esconder e public no que queria exibir.\nHoje, depois de muito tempo e um pouco de experiência, eu vi que aprendemos tudo ao contrário.\nA orientação a objetos serve para muito mais do que o reaproveitamento de código. Hoje existem algumas literaturas (que vou indicar nas próximas partes) que dizem que a prioridade da orientação a objetos é a qualidade e legibilidade do nosso código, e os mecanismos de herança devem ser usados com muito cuidado.\nDentre a tríade de poderes da orientação a objetos (daqui para frente, apenas OO), a prioridade que devemos tratar deve ser contrária ao que costumamos aprender, devendo ser o encapsulamento tratado como prioridade, o polimorfismo e todo o seu dinamismo em segundo, e a herança usada apenas em momentos que realmente faz sentido uma classe ser filha de outra. Essa ordem permite que o software seja desenvolvido de maneira defensiva, ou seja, cada parte do seu código está protegida e fazendo apenas o que deve, seguindo diversos princípios que tornam fácil essa manutenção,diminuindo o acoplamento do código e a dependência entre módulos.\nReconsiderar o que já sabemos pode ser estranho, principalmente se você tem apenas o conhecimento da faculdade ou cursos como base, porém é necessário entender o que cada recurso prove para podermos assim trabalhar da maneira correta e menos desgastante. Nas próximas partes, vamos tratar assunto por assunto da OO, vendo através de exemplos como ter um código mais limpo, bonito e elegante.\n*Na verdade, a orientação a objetos realmente facilita o tratamento de objetos gráficos, pois com ela fica mais simples definir propriedades e ações dos mesmos, criando uma ligação direta entre o código e os eventos dos objetos.\n","permalink":"https://blog.lucaspolo.dev/posts/desconstruindo-a-orientacao-a-objetos-ou-esquecendo-o-que-voce-aprendeu-na-escol/","summary":"\u003cp\u003eLembro-me como se fosse ontem (que poético isso) a primeira vez que eu ouvi sobre a orientação a objetos. Depois de muito tempo lidando com linguagens puramente procedurais (C, COBOL, Visual Basic), eu ouvi falar sobre esse novo paradigma e é claro, sobre uma das linguagens que usa ele, o Java. A primeira coisa que eu ouvi foi \u0026ldquo;a orientação a objetos é ótima para construir interfaces gráficas\u0026rdquo;, e eu sei, que se você tem o mínimo de noção sobre o que é orientação a objetos, sabe que isso foi uma enorme canelada*.\u003c/p\u003e","title":"Desconstruindo a Orientação a Objetos (ou esquecendo o que você aprendeu na escola) - Parte 1"},{"content":"Não podemos ter um blog de programação sem uma das coisas mais úteis que o programador usa para destacar a facilitar a leitura de seu código, o syntax highlight! Uma rápida pesquisa me retornou uma das bibliotecas mais usadas para tratar isso, o SyntaxHighlighter.\nSua instalação é muito simples, em dois minutos eu consegui incorporar as bibliotecas no blog e já fiz o código a seguir usando ele.\nUm pequeno teste, instalando o SyntaxHighlighter no blog:\nfor(int i = 0; i \u0026lt; 10; i++) { System.out.println(\u0026#34;Com a sintaxe destacada!\u0026#34;); } Aqui está o tutorial que eu utilizei para instalar a biblioteca. E para dizer que não contribui com algo que não fosse apenas divulgar, fica a dica: Coloque apenas as bibliotecas que for utilizar, pois desta forma você não deixa o carregamento do site lento. No meu caso, você pode inspecionar o código, eu coloquei todas, porém deixei a maior parte dentro de um bloco de comentário, caso precise utilizar uma nova, basta move-lo.\n","permalink":"https://blog.lucaspolo.dev/posts/syntax-highlighting-no-blog/","summary":"\u003cp\u003eNão podemos ter um blog de programação sem uma das coisas mais úteis que o programador usa para destacar a facilitar a leitura de seu código, o syntax highlight! Uma rápida pesquisa me retornou uma das bibliotecas mais usadas para tratar isso, o \u003ca href=\"http://alexgorbatchev.com/SyntaxHighlighter\"\u003eSyntaxHighlighter\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eSua instalação é muito simples, em dois minutos eu consegui incorporar as bibliotecas no blog e já fiz o código a seguir usando ele.\u003c/p\u003e\n\u003cp\u003eUm pequeno teste, instalando o SyntaxHighlighter no blog:\u003c/p\u003e","title":"Syntax highlighting no blog"},{"content":"A pergunta do título com certeza tem mais de uma resposta, se você está na área de desenvolvimento já sabe disso. Uma pessoa que escolhe ser programador, apesar de ter filtrado todas as possíveis áreas da tecnologia da informação (aka T.I.), ainda precisa se decidir dentro da área de desenvolvimento o que fazer, quais tecnologias usar, quais paradigmas dominar e por ai segue. Trilhar esse caminho da maneira correta, sabendo quais escolhas fazer, o quer deixar para trás e para onde ir é o que separa os que apenas trabalham na área dos que realmente gostam de programar.\nCerta vez um instrutor de programação disse para uma turma de Java Enterprise da qual eu estava participando a seguinte frase: \u0026ldquo;Você pode gostar do que está fazendo, ou fazer o que gosta\u0026rdquo;, infelizmente, muito do que vejo na área hoje em dia é que uma pequena parte dos profissionais realmente gostam de programar e escolheram isso como sua vocação para a vida. Uma segunda parte programa apenas porque é a sua profissão, fazendo disso um meio de vida e na medida do possível trabalhando da maneira mais correta possível, porém, essas pessoas não buscam inovar dentro da sua área, pois o objetivo profissional delas não esta alinhado com a área que segue.\nO intuito deste blog não é mostrar o caminho correto e nem dizer o que é certo ou errado, o intuito é mostrar a minha jornada dentro da área, minhas decisões, o que estou fazendo, meus códigos (eu quero encher o blog de códigos =D ) e também, é claro, as minhas frustrações. Pretendo seguir uma linha de temas variados, entre assuntos técnicos e profissionais, tudo o que está relacionado a nossa área (se você chegou até aqui, você é a resistência).\nApenas para acrescentar, hoje a minha linha de estudo se baseia na linguagem Java, porém gosto e uso outras linguagens, como Shell Script, C/C++, Perl, Informix-4GL e Python. Também gosto de eletrônica, que aprendi muito antes da programação e hoje sou um dos amantes da dupla Arduíno e Raspberry PI.\nAvante Programadores!\n","permalink":"https://blog.lucaspolo.dev/posts/qual-o-caminho-do-programador/","summary":"\u003cp\u003eA pergunta do título com certeza tem mais de uma resposta, se você está na área de desenvolvimento já sabe disso. Uma pessoa que escolhe ser programador, apesar de ter filtrado todas as possíveis áreas da tecnologia da informação (aka T.I.), ainda precisa se decidir dentro da área de desenvolvimento o que fazer, quais tecnologias usar, quais paradigmas dominar e por ai segue. Trilhar esse caminho da maneira correta, sabendo quais escolhas fazer, o quer deixar para trás e para onde ir é o que separa os que apenas trabalham na área dos que realmente gostam de programar.\u003c/p\u003e","title":"Qual o caminho do programador?"}]