<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Samuel Rodrigues Almeida e Sousa</title>
    <description>The latest articles on DEV Community by Samuel Rodrigues Almeida e Sousa (@samuelralmeida).</description>
    <link>https://dev.to/samuelralmeida</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F862507%2F8c1316f5-6f8a-4adc-b2af-8fa260391541.jpeg</url>
      <title>DEV Community: Samuel Rodrigues Almeida e Sousa</title>
      <link>https://dev.to/samuelralmeida</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samuelralmeida"/>
    <language>en</language>
    <item>
      <title>O que achei do Bootcamp Java com Spring Boot organizado pela Dio e Claro</title>
      <dc:creator>Samuel Rodrigues Almeida e Sousa</dc:creator>
      <pubDate>Thu, 21 Nov 2024 19:47:37 +0000</pubDate>
      <link>https://dev.to/samuelralmeida/o-que-achei-do-bootcamp-java-com-spring-boot-organizado-pela-dio-e-claro-4c0p</link>
      <guid>https://dev.to/samuelralmeida/o-que-achei-do-bootcamp-java-com-spring-boot-organizado-pela-dio-e-claro-4c0p</guid>
      <description>&lt;h2&gt;
  
  
  introdução
&lt;/h2&gt;

&lt;p&gt;Descobri por acaso o &lt;a href="https://www.dio.me/bootcamp/coding-the-future-claro-java-spring-boot" rel="noopener noreferrer"&gt;Bootcamp Java com Spring Boot organizado pela Dio e Claro&lt;/a&gt; e resolvi fazer por dois motivos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gosto de programar e conhecer uma linguagem nova de programação é tipo um hobby&lt;/li&gt;
&lt;li&gt;Java é uma linguagem bastante usada no mercado e historicamente importante.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Após concluir o bootcamp resolvi escrever minhas impressões sobre o curso.&lt;/p&gt;

&lt;p&gt;Os desafios que fiz durante o curso estão no github: &lt;a href="https://github.com/samuelralmeida/exercises-dio-java" rel="noopener noreferrer"&gt;https://github.com/samuelralmeida/exercises-dio-java&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  sobre o objetivo do curso
&lt;/h2&gt;

&lt;p&gt;Na página de apresentação do curso aparece qual é o perfil do público destinado o curso e o objetivo dele:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Profissionais que desejam entrar ou evoluir suas práticas no mercado como desenvolvedor back-end construindo e implementando APIs com Java e Spring, com foco em arquitetura de microsserviços que destacam o portfólio.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Se prepare para as oportunidades que estão por vir e tenha sucesso nas entrevistas de recrutamento.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Pelo texto eu entendi que o público alvo é tanto pessoas que não são desenvolvedores profissionais e querem se tornar, quanto pessoas que já trabalham com desenvolvimento e querem se preparar.&lt;/p&gt;

&lt;p&gt;Para quem está tentando entrar na área, o curso deve ser entendido como um complemento de estudos que precisam ser mais amplos. O estudante que começa esse bootcamp achando que vai ser o suficiente para um conhecimento básico para tentar entrevistas de emprego ficará frustrado. Penso que ele vai precisar de outros cursos para estar apto a essa busca.&lt;/p&gt;

&lt;p&gt;Para quem já trabalha com programação, meu caso, o curso é bom para conhecer uma nova linguagem e framework. Não acho que um desenvolvedor júnior ou pleno fazendo o curso se sentirá pronto para o próximo nível de carreira, mas com certeza ajuda nessa bagagem.&lt;/p&gt;

&lt;h2&gt;
  
  
  sobre o curso e minha experiência
&lt;/h2&gt;

&lt;p&gt;Eu não conhecia nada de Java e trabalhei pouco com orientação a objeto até o momento. Então o curso foi ótimo para conhecer a sintaxe da linguagem, framework, pacotes, recursos, etc.&lt;/p&gt;

&lt;p&gt;Não me sinto capaz de liderar um sistema de produção em Java com o que eu aprendi, mas, juntando com minhas outras experiências anteriores de outros trabalhos e linguagens, acredito ser capaz de colaborar com um time que trabalha com Java e com o tempo dominar melhor esse conhecimento.&lt;/p&gt;

&lt;p&gt;Tenho mais experiência trabalhando com linguagens que não são baseadas em orientação a objetos. O curso me ajudou muito a conhecer mais esse paradigma, que é a base do Java.&lt;/p&gt;

&lt;p&gt;O curso mescla alguns vídeos gravados mais recentes com outros mais antigos. Não me parece ter uma grande perda por isso, mas é estranho um bootcamp de Java com Spring Boot ter aulas usando Java 8 sendo que a menor versão do “spring initializr” é 17. Isso gera alguns problemas de compatibilidade ao usar Gradle ou Maven, mas ter que resolvê-los foi de muito aprendizado também.&lt;/p&gt;

&lt;p&gt;Os professores são bons e a plataforma de aula também é boa. Sempre cabe espaço para melhorar, mas não senti que me atrapalhou em nada. O bootcamp conta com mentorias que são aulas ou conversas com experts, acontecem ao vivo, mas ficam gravadas também. Não assisti todas, mas ouvir a experiência de gente programando ou liderando times na vida real é sempre legal. Ter esses momentos é sempre positivo para mim.&lt;/p&gt;

&lt;p&gt;O curso tem alguns projetos para fazer e colocar no portfólio. Não são projetos complexos e muito elaborados que vão chamar muita atenção se você já atua como desenvolvedor, entretanto, para quem está tentando entrar na área, é sempre importante ter esses projetos para treinar e mostrar.&lt;/p&gt;

&lt;h2&gt;
  
  
  sobre meu aprendizado
&lt;/h2&gt;

&lt;p&gt;Acredito que o que eu tinha para falar do bootcamp em si eu já falei antes. Então agora é sobre o que eu aprendi.&lt;/p&gt;

&lt;p&gt;Para meus objetivos pessoais de aprender uma nova linguagem como hobby e possibilitar oportunidades de trabalho, fiquei satisfeito. &lt;/p&gt;

&lt;p&gt;Sobre o quesito hobby, achei uma linguagem chata por ser muito verbosa mesmo com as facilidades do Spring Boot e Stream API. Além disso, o Spring Boot é um framework que usa muito de decoradores e abstrações e isso deixa as coisas meio “mágicas” no código, realmente pode trazer produtividade, mas por vezes eu tinha dificuldade de ler o código e saber exatamente o que estava acontecendo. Pessoalmente, não seria uma linguagem que escolheria para fazer um projeto.&lt;/p&gt;

&lt;p&gt;Sobre o quesito profissional, entendo linguagens de programação como uma ferramenta de trabalho, não acho correto me limitar a uma outra linguagem para trabalhar. Então com o conhecimento básico de Java que aprendi no curso acredito que posso me comunicar bem com times que trabalham com Java Spring Boot, talvez tenha uma certa dificuldade inicial de entender completamente o código devido às muita abstrações do framework e com o tempo e prática poderia colaborar melhor com o desenvolvimento de sistemas em Java.&lt;/p&gt;

</description>
      <category>java</category>
      <category>backend</category>
      <category>learning</category>
    </item>
    <item>
      <title>LGPD e falsear dados sensíveis no banco de dados - parte 2</title>
      <dc:creator>Samuel Rodrigues Almeida e Sousa</dc:creator>
      <pubDate>Mon, 13 Jun 2022 18:09:15 +0000</pubDate>
      <link>https://dev.to/samuelralmeida/lgpd-e-falsear-dados-sensiveis-no-banco-de-dados-parte-2-3b7b</link>
      <guid>https://dev.to/samuelralmeida/lgpd-e-falsear-dados-sensiveis-no-banco-de-dados-parte-2-3b7b</guid>
      <description>&lt;h2&gt;
  
  
  Contextualizando
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://www.gov.br/cidadania/pt-br/acesso-a-informacao/lgpd" rel="noopener noreferrer"&gt;Lei Geral de Proteção de Dados Pessoais (LGPD)&lt;/a&gt; visa regulamentar direitos e deveres no tratamento de dados pessoais. Participando de conversas sobre o tema, o time que trabalho chegou a conclusão que é mais seguro e inteligente que os bancos de dados de desenvolvimento e &lt;em&gt;staging&lt;/em&gt; não tivessem dados pessoais reais dos clientes por alguns motivos:&lt;/p&gt;

&lt;p&gt;a) como os desenvolvedores trabalham de forma remota o acesso a esses bancos é mais aberto.&lt;/p&gt;

&lt;p&gt;b) uma vez que não é necessário aos ambientes de desenvolvimento e staging que existam dados reais, é mais seguro e eficiente não tê-los do que criar estratégias e recursos para protegê-los.&lt;/p&gt;

&lt;h2&gt;
  
  
  O desafio
&lt;/h2&gt;

&lt;p&gt;Nosso banco de produção possui dois &lt;em&gt;databases&lt;/em&gt; importantes que possuem dados sensíveis para serem falseados e disponibilizados em desenvolvimento e &lt;em&gt;staging.&lt;/em&gt; O desafio foi gerar um programa que automatize esse processo de gerar um banco com dados falsos a partir do de produção; ainda é necessário que seja possível escolher qual &lt;em&gt;database&lt;/em&gt; de origem e qual ambiente de destino.&lt;/p&gt;

&lt;p&gt;Um rascunho seria:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fazer a cópia do banco de produção (&lt;strong&gt;parte 1&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Inserir essa cópia em um banco temporário (&lt;strong&gt;parte 1&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Falsear os dados sensíveis&lt;/li&gt;
&lt;li&gt;Fazer uma nova cópia com os dados falsos (&lt;strong&gt;parte 1&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Inserir no bancos de desenvolvimento e/ou staging (&lt;strong&gt;parte 1&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Excluir arquivos intermediários gerados&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;Por motivos de segurança da informação os databases, tabelas e colunas serão inventados. Além disso, os exemplos usam tabelas menores e mais simples, uma vez que o objetivo é mostrar e explicar o código desenvolvido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parte 1
&lt;/h2&gt;

&lt;p&gt;A parte 1 aborda mais a manipulação do banco de dados usando os clientes &lt;strong&gt;mysql&lt;/strong&gt; e &lt;strong&gt;mysqldump&lt;/strong&gt; pode ser lido aqui: &lt;/p&gt;

&lt;h2&gt;
  
  
  Parte 2
&lt;/h2&gt;

&lt;p&gt;O programa foi feito em Golang e o chamei de &lt;strong&gt;fakedb&lt;/strong&gt;. Essa segunda parte aborda como o &lt;strong&gt;fakedb&lt;/strong&gt; gera dados falsos e atualiza o banco. Além disso, tabelas em banco podem ser cridas, colunas adicionadas ou removidas, então o código precisa permitir essa dinamicidade também.&lt;/p&gt;

&lt;p&gt;O código completo pode ser acessado em &lt;a href="https://github.com/samuelralmeida/fakedb" rel="noopener noreferrer"&gt;https://github.com/samuelralmeida/fakedb&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Organização do código e interfaces do script
&lt;/h3&gt;

&lt;p&gt;Cada &lt;em&gt;database&lt;/em&gt; do banco possui um diretório. No nosso exemplo: &lt;a href="https://github.com/samuelralmeida/fakedb/tree/main/fakedata/dbs/coisadb" rel="noopener noreferrer"&gt;&lt;strong&gt;coisa&lt;/strong&gt;&lt;/a&gt; e &lt;a href="https://github.com/samuelralmeida/fakedb/tree/main/fakedata/dbs/tremdb" rel="noopener noreferrer"&gt;&lt;strong&gt;trem&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dentro desse diretório cada tabela que precisar falsear dados tem um arquivo próprio, além de um arquivo “pai” com o mesmo nome do &lt;em&gt;database&lt;/em&gt; que retorna o grupo de scripts por tabela que devem ser executados.&lt;/p&gt;

&lt;p&gt;As duas interfaces abaixo definem as regras a serem seguidas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// arquivo fakedata/interface.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;fakedata&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"database/sql"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;FakeDataScript&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;
    &lt;span class="n"&gt;FetchRows&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;PrepareStmt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;UpdateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;IFakeData&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Scripts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;FakeDataScript&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada script da tabela atende a interface &lt;strong&gt;FakeDataScript&lt;/strong&gt; e cada &lt;em&gt;database&lt;/em&gt; atende a interface &lt;strong&gt;IFakeData&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dessa forma, uma alteração em uma tabela existente só precisa ser corrigida no seu respectivo script. Uma nova tabela que surgir, basta escrever os métodos para ela e devolver no array do database.&lt;/p&gt;

&lt;h3&gt;
  
  
  A estrutura do script de falsear dados
&lt;/h3&gt;

&lt;p&gt;Como para cada tabela do banco temos os mesmo métodos definidos pela interface, o que o programa faz é os chamar de forma lógica. Vou detalhar o que ocorre no arquivo &lt;a href="https://github.com/samuelralmeida/fakedb/blob/main/script/fake_data.go" rel="noopener noreferrer"&gt;fake_data.go&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A função &lt;code&gt;getDBHandle&lt;/code&gt; cria uma conexão com banco a partir das credenciais recebidas.&lt;/li&gt;
&lt;li&gt;Para cada tabela do &lt;em&gt;database&lt;/em&gt; passado vai:
2.1. Buscar todas as entradas da tabela. (método &lt;code&gt;FetchRows&lt;/code&gt;)
2.2. Iniciar uma transaction para garantir que todas as alterações sejam feitas por inteiro ou nada seja feito
2.3. Preparar um &lt;em&gt;statement&lt;/em&gt; a partir da transaction com o UPDATE da respectiva tabela. (método &lt;code&gt;PrepareStmt&lt;/code&gt;)
2.4. Atualizar os dados falsos. (método &lt;code&gt;UpdateData&lt;/code&gt;)
2.5. Fazer o &lt;em&gt;commit&lt;/em&gt; da transaction.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;É dentro do &lt;code&gt;UpdateData&lt;/code&gt; que o principal ocorre:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;FakeClientTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UpdateData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rows scan error: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;cpf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateCpf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateAddress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"update exec error: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rows error: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código acima é do exemplo para a tabela de cliente. O método recebe as linhas retornadas do banco e o &lt;em&gt;statement&lt;/em&gt; de update; para cada linha um novo nome, CPF e endereço é gerado e a linha é atualizada usando o &lt;code&gt;Exec&lt;/code&gt; do &lt;em&gt;statement&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Para gerar os dados falsos usamos o pacote &lt;a href="https://github.com/brianvoe/gofakeit" rel="noopener noreferrer"&gt;gogakeit&lt;/a&gt;. Ele pode ser chamado diretamente como no caso da tabela de &lt;a href="https://github.com/samuelralmeida/fakedb/blob/main/fakedata/dbs/coisadb/lead.go#L49" rel="noopener noreferrer"&gt;&lt;em&gt;lead&lt;/em&gt;&lt;/a&gt;: &lt;code&gt;email := gofakeit.Email()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Deixei esse caso de exemplo, mas acredito que o melhor é encapsular dentro do nosso pacote &lt;em&gt;helper&lt;/em&gt; caso queira ou precise alterar o pacote &lt;strong&gt;gofakeit:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// fakedata/helper/generate_data.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/brianvoe/gofakeit/v6"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GenerateAddress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Avenida"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Rua"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Travessa"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;street&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s %s %s, %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;gofakeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="n"&gt;gofakeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreetPrefix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;gofakeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreetName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;gofakeit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;street&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  O caso CPF
&lt;/h3&gt;

&lt;p&gt;O &lt;strong&gt;gofakeit&lt;/strong&gt; não gera CPFs e é importante que eles sejam válidos para que não quebre validações que existam no back ou frontend. Além disso, CPFs costumam ser chave única no banco, portanto, apesar de ser gerado aleatório não pode ser repetidos. Por isso criamos uma função para gerar cpfs falsos &lt;a href="https://github.com/samuelralmeida/fakedb/blob/main/fakedata/helper/cpf.go" rel="noopener noreferrer"&gt;cpf.go&lt;/a&gt; que controla quais já foram gerados usando um &lt;em&gt;map&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLI, Dockerfile e Makefile
&lt;/h3&gt;

&lt;p&gt;Usamos o pacote &lt;strong&gt;flag&lt;/strong&gt; nativo do Go para permitir parâmetros na chamada para definir quais databases de origem dos dados, no nosso exemplo permite &lt;strong&gt;trem&lt;/strong&gt;, &lt;strong&gt;coisa&lt;/strong&gt; ou &lt;strong&gt;all&lt;/strong&gt; (default). E também decidir o destino &lt;strong&gt;dev&lt;/strong&gt;, &lt;strong&gt;staging&lt;/strong&gt; ou &lt;strong&gt;all&lt;/strong&gt; (default):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.go&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Specify which database. Options: all, trem, coisa. Default: all"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Specify which dump destination. Options: all, dev, staging. Default: all"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"all"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"trem"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"coisa"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"all"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"dev"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"staging"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is a invalid source. Options: all, farme, indicame."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s is a invalid target. Options: all, dev, staging."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optamos por usar um container Docker para rodar o script para padronizar o ambiente que é executado e facilita subir a imagem e rodar o container em uma máquina da AWS.&lt;/p&gt;

&lt;p&gt;Usamos uma imagem de Go intermediária para compilar o programa e uma imagem definitiva do Mysql que já sobe um banco local automaticamente ao iniciar o container. E copiamos o executável do nosso programa para essa imagem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;// Dockerfile
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; fakedb main.go

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mysql:8.0.23&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;app
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/fakedb /app&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para facilitar executar e automatizar o programa preparamos um Makefile que facilita a fazer build da imagem, iniciar o container, acessar e executar o container, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker build &lt;span class="nt"&gt;-t&lt;/span&gt; dumpfakedb .

&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; dumpfakedb &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env dumpfakedb

&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; dumpfakedb bash

&lt;span class="nl"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker container &lt;span class="nb"&gt;rm &lt;/span&gt;dumpfakedb &lt;span class="nt"&gt;-f&lt;/span&gt;

&lt;span class="nl"&gt;fakedb-all&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; dumpfakedb ./fakedb

&lt;span class="nl"&gt;fakedb-all-dev&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; dumpfakedb ./fakedb &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev

&lt;span class="nl"&gt;fakedb-trem-staging&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; dumpfakedb ./fakedb &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;trem &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;staging
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fim
&lt;/h2&gt;

&lt;p&gt;Essa foi a segunda parte que abordou mais o falseamento dos dados e execução do programa. O artigo ficou um pouco grande e denso devido aos detalhes do assunto e do código, mas espero que tenha ajudado você. Até breve.&lt;/p&gt;

</description>
      <category>database</category>
      <category>programming</category>
      <category>go</category>
      <category>security</category>
    </item>
    <item>
      <title>LGPD e falsear dados sensíveis no banco de dados de dev e staging - parte 1</title>
      <dc:creator>Samuel Rodrigues Almeida e Sousa</dc:creator>
      <pubDate>Mon, 30 May 2022 16:09:04 +0000</pubDate>
      <link>https://dev.to/samuelralmeida/lgpd-e-falsear-dados-sensiveis-no-banco-de-dados-de-dev-e-staging-parte-1-3adb</link>
      <guid>https://dev.to/samuelralmeida/lgpd-e-falsear-dados-sensiveis-no-banco-de-dados-de-dev-e-staging-parte-1-3adb</guid>
      <description>&lt;h2&gt;
  
  
  Contextualizando
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="[https://www.gov.br/cidadania/pt-br/acesso-a-informacao/lgpd](https://www.gov.br/cidadania/pt-br/acesso-a-informacao/lgpd)"&gt;Lei Geral de Proteção de Dados Pessoais (LGPD)&lt;/a&gt; visa regulamentar direitos e deveres no tratamento de dados pessoais. Participando de conversas sobre o tema, o time que trabalho chegou a conclusão que é mais seguro e inteligente que os bancos de dados de desenvolvimento e &lt;em&gt;staging&lt;/em&gt; não tivessem dados pessoais reais dos clientes por alguns motivos:&lt;/p&gt;

&lt;p&gt;a) como os desenvolvedores trabalham de forma remota o acesso a esses bancos é mais aberto.&lt;/p&gt;

&lt;p&gt;b) uma vez que não é necessário aos ambientes de desenvolvimento e staging que existam dados reais, é mais seguro e eficiente não tê-los do que criar estratégias e recursos para protegê-los.&lt;/p&gt;

&lt;h2&gt;
  
  
  O desafio
&lt;/h2&gt;

&lt;p&gt;Nosso banco de produção possui dois &lt;em&gt;databases&lt;/em&gt; importantes que possuem dados sensíveis para serem falseados e disponibilizados em desenvolvimento e &lt;em&gt;staging.&lt;/em&gt; O desafio foi gerar um programa que automatize esse processo de gerar um banco com dados falsos a partir do de produção; ainda é necessário que seja possível escolher qual &lt;em&gt;database&lt;/em&gt; de origem e qual ambiente de destino.&lt;/p&gt;

&lt;p&gt;Um rascunho seria:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fazer a cópia do banco de produção&lt;/li&gt;
&lt;li&gt;Inserir essa cópia em um banco temporário&lt;/li&gt;
&lt;li&gt;Falsear os dados sensíveis (&lt;strong&gt;parte 2&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Fazer uma nova cópia com os dados falsos&lt;/li&gt;
&lt;li&gt;Inserir no bancos de desenvolvimento e/ou staging&lt;/li&gt;
&lt;li&gt;Excluir arquivos intermediários gerados (&lt;strong&gt;parte 2&lt;/strong&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;Por motivos de segurança da informação os &lt;em&gt;databases&lt;/em&gt;, tabelas e colunas serão inventados. Além disso, os exemplos usam tabelas menores e mais simples, uma vez que o objetivo é mostrar e explicar o código desenvolvido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parte 1
&lt;/h2&gt;

&lt;p&gt;O programa foi feito em Golang e o chamei de &lt;strong&gt;fakedb&lt;/strong&gt;. Essa primeira parte aborda como o &lt;strong&gt;fakedb&lt;/strong&gt; usa os recursos dos clientes CLI &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/mysql.html" rel="noopener noreferrer"&gt;mysql&lt;/a&gt;) e &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html" rel="noopener noreferrer"&gt;mysqldump&lt;/a&gt;) para resolver os itens 1, 2, 4 e 5 do rascunho apresentado anteriormente.&lt;/p&gt;

&lt;p&gt;O código completo pode ser acessado em &lt;a href="https://github.com/samuelralmeida/fakedb" rel="noopener noreferrer"&gt;https://github.com/samuelralmeida/fakedb&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A estrutura do banco de produção
&lt;/h3&gt;

&lt;p&gt;O código SQL para gerar o banco de produção com dados para nosso código se encontra no arquivo &lt;a href="https://github.com/samuelralmeida/fakedb/blob/main/populate.sql" rel="noopener noreferrer"&gt;&lt;code&gt;populate.sql&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Go exec&lt;/em&gt;, &lt;em&gt;mysql&lt;/em&gt; e &lt;em&gt;mysqldump&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;mysql&lt;/em&gt; e &lt;em&gt;mysqldump&lt;/em&gt; são clientes CLI para manipular bancos de forma direta, por exemplo, o código abaixo cria o database &lt;em&gt;temp&lt;/em&gt; diretamente pelo terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysql &lt;span class="nt"&gt;-user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="nt"&gt;--password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;minha_senha &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"CREATE DATABASE temp"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Golang oferece um pacote nativo &lt;a href="https://pkg.go.dev/os/exec" rel="noopener noreferrer"&gt;os/exec&lt;/a&gt; que permite executar pelo código comandos de terminal. O exemplo abaixo faz o mesmo que o código anterior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"os/exec"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;dropDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--user=root"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--password=minha_senha"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"CREATE DATABASE temp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O arquivo &lt;a href="https://github.com/samuelralmeida/fakedb/blob/main/mysqldb/mysqldb.go" rel="noopener noreferrer"&gt;&lt;code&gt;mysqldb&lt;/code&gt;&lt;/a&gt; contem as funções que usamos para deletar o database se existir (DropDatabase), criar um database (CreateDatabase), exportar dados (DumpDatabase), importar dados (RestoreData).&lt;/p&gt;

&lt;p&gt;Função de exportar dados recebe o nome do arquivo sql que vai ser gerado. No terminal seria similar a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mysqldump&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prod_trem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já a função para importar os dados recebe o nome do arquivo que possui os dados para serem inseridos, no terminal teriamos algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;prod_trem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa particularidade do arquivo ser um input para o cliente mysql faz com que precisamos abrir o arquivo em buffer e controlar o &lt;em&gt;stdin&lt;/em&gt; no Go para usá-lo junto com o &lt;em&gt;mysql&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;RestoreData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionParams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"restoreData: error to read file: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;dropArgs&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--host=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--port=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--user=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--password=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dropArgs&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StdinPipe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"restoreData: error to get stdin pipe: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CombinedOutput&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"restoreData: error to run command: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;em&gt;Goroutines&lt;/em&gt; para restaurar dados
&lt;/h3&gt;

&lt;p&gt;As etapas mais demoradas são: a) fazer o dump do banco, que por ser de um único banco não tem como fazer em paralelo; e b) restaurar os dados em um novo database, o que podemos melhorar a performance paralelizando essa etapa uma vez que a restauração ocorre para bancos de &lt;em&gt;dev&lt;/em&gt; e &lt;em&gt;staging&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O código abaixo mostra como abrimos uma &lt;em&gt;goroutine&lt;/em&gt; para cada banco alvo, controlamos os possíveis erros de forma independente e aguardamos que finalizem usando &lt;a href="https://pkg.go.dev/sync#WaitGroup" rel="noopener noreferrer"&gt;&lt;em&gt;sync.WaitGroup&lt;/em&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// goroutine para alvos&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;restoreTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionParams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;   &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
        &lt;span class="n"&gt;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;

        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionParams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"drop database if exixts - %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysqldb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DropDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target - %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"create database - %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysqldb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target - %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"restore database - %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysqldb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RestoreData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"target - %s: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DONE: restore database - %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;amp;&amp;amp;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Empregamos esse mesmo raciocínio para executar o script em paralelo para bancos diferentes, uma &lt;em&gt;goroutine&lt;/em&gt; para o banco &lt;strong&gt;trem&lt;/strong&gt; e outra para o banco &lt;strong&gt;coisa&lt;/strong&gt;, como pode ser visto no arquivo &lt;code&gt;main.go&lt;/code&gt;. Nos nossos testes, o uso de &lt;em&gt;goroutines&lt;/em&gt; nos fez economizar 30% do tempo gasto sem elas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Acessando bancos por variáveis de ambiente
&lt;/h3&gt;

&lt;p&gt;Para não deixar como &lt;em&gt;hardcode&lt;/em&gt; dados de acesso aos bancos, usamos variáveis de ambiente que são carregadas dentro do container docker que roda todo o script. As variáveis ficam em um arquivo &lt;code&gt;.env&lt;/code&gt;, e no arquivo &lt;code&gt;example.env&lt;/code&gt; tem um esqueleto dessas variáveis.&lt;/p&gt;

&lt;p&gt;A imagem docker criada para executar o script se baseia em uma imagem do &lt;a href="https://hub.docker.com/_/mysql" rel="noopener noreferrer"&gt;Docker do Mysql&lt;/a&gt;, que já vem com os clientes &lt;code&gt;mysql&lt;/code&gt; e &lt;code&gt;mysldump&lt;/code&gt; instalados. Além disso, usando a variável de ambiente &lt;code&gt;MYSQL_ROOT_PASSWORD&lt;/code&gt;, já inicia um banco local dentro do container o usado como banco intermediário para receber os dados de produção, falsear e exportar. Por isso a mesma senha dele é usada na variável de ambiente &lt;code&gt;INTERMEDIATE_PASS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A vantagem de usar esse banco local do container como intermediário, é que finalizando o script e removendo o container, todos os dados intermediários que o script gerou são apagados também.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continua…
&lt;/h2&gt;

&lt;p&gt;Essa primeira parte abordou mais a manipulação dos bancos, a segunda parte vai ser a respeito da lógica para gerar dados falsos para o banco. O artigo ficou um pouco grande e denso devido aos detalhes do assunto e do código, mas espero que tenha ajudado você. Até breve.&lt;/p&gt;

</description>
      <category>database</category>
      <category>programming</category>
      <category>go</category>
      <category>security</category>
    </item>
  </channel>
</rss>
