<?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>Forem: Pinei</title>
    <description>The latest articles on Forem by Pinei (@pinei).</description>
    <link>https://forem.com/pinei</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%2F350303%2Fab1fdfc0-9306-495d-8b48-6bad0d33bceb.jpeg</url>
      <title>Forem: Pinei</title>
      <link>https://forem.com/pinei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/pinei"/>
    <language>en</language>
    <item>
      <title>Uso de "skills" e abordagem "spec-driven" com Claude Code</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Wed, 01 Apr 2026 18:17:43 +0000</pubDate>
      <link>https://forem.com/pinei/uso-de-skills-e-abordagem-spec-driven-com-claude-code-4j3m</link>
      <guid>https://forem.com/pinei/uso-de-skills-e-abordagem-spec-driven-com-claude-code-4j3m</guid>
      <description>&lt;p&gt;O &lt;strong&gt;Claude Code&lt;/strong&gt; é um ambiente de codificação agentivo: ele não apenas responde perguntas, mas pode &lt;strong&gt;ler a base de código, editar arquivos, executar comandos e verificar resultados&lt;/strong&gt; ao longo de um loop de trabalho que combina entendimento, ação e validação. Além disso, ele pode ser usado no terminal, IDE, desktop e navegador, com um mesmo conjunto de instruções e extensões compartilhadas entre esses ambientes.&lt;/p&gt;

&lt;p&gt;Dentro desse modelo, duas ideias se destacam para ganhar consistência e escala: &lt;strong&gt;skills&lt;/strong&gt; e uma forma de trabalhar orientada por &lt;strong&gt;especificações&lt;/strong&gt; (&lt;em&gt;spec-driven&lt;/em&gt;). As &lt;em&gt;skills&lt;/em&gt; são extensões em Markdown que adicionam conhecimento, workflows reutilizáveis e comandos invocáveis ao Claude Code; já o &lt;em&gt;spec-driven&lt;/em&gt; não aparece como um “recurso oficial” com esse nome, mas é uma &lt;strong&gt;estratégia de uso&lt;/strong&gt; totalmente alinhada às práticas que a Anthropic recomenda: partir de uma especificação clara, decompor o trabalho, definir critérios de verificação e manter artefatos estruturados ao longo da execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que são &lt;em&gt;skills&lt;/em&gt; no Claude Code
&lt;/h2&gt;

&lt;p&gt;No Claude Code, uma &lt;em&gt;skill&lt;/em&gt; é uma capacidade modular definida em um arquivo &lt;code&gt;SKILL.md&lt;/code&gt;. Esse arquivo pode conter &lt;strong&gt;frontmatter YAML&lt;/strong&gt; com metadados — como nome, descrição, ferramentas permitidas e modo de invocação — seguido por instruções em Markdown que orientam o comportamento do agente quando a &lt;em&gt;skill&lt;/em&gt; é acionada. O Claude pode carregar uma &lt;em&gt;skill&lt;/em&gt; automaticamente quando ela parece relevante para a solicitação do usuário, ou o usuário pode chamá-la explicitamente por meio de um comando como &lt;code&gt;/nome-da-skill&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As &lt;em&gt;skills&lt;/em&gt; são importantes porque funcionam como uma camada entre o “conhecimento genérico” do modelo e as necessidades específicas do seu time ou projeto. Em vez de repetir o mesmo prompt toda vez — por exemplo, “revise este código considerando segurança, performance e compatibilidade” — você embute esse raciocínio em uma &lt;em&gt;skill&lt;/em&gt; reutilizável. Isso reduz ambiguidade, melhora a repetibilidade e separa melhor o que é &lt;strong&gt;regra do projeto&lt;/strong&gt; do que é &lt;strong&gt;tarefa pontual&lt;/strong&gt;. A própria documentação do Claude Code posiciona as &lt;em&gt;skills&lt;/em&gt; como a extensão mais flexível do ecossistema, ao lado de &lt;code&gt;CLAUDE.md&lt;/code&gt;, hooks, subagentes e MCP.&lt;/p&gt;

&lt;p&gt;Outro ponto forte é o controle fino de comportamento. Uma &lt;em&gt;skill&lt;/em&gt; pode, por exemplo, ser marcada com &lt;code&gt;disable-model-invocation: true&lt;/code&gt; para que &lt;strong&gt;só o usuário&lt;/strong&gt; a execute manualmente, o que é útil em ações sensíveis como &lt;em&gt;deploy&lt;/em&gt; ou criação de commit. Também pode usar &lt;code&gt;allowed-tools&lt;/code&gt; para limitar as ferramentas liberadas durante sua execução, e &lt;code&gt;context: fork&lt;/code&gt; para rodar em &lt;strong&gt;subagente isolado&lt;/strong&gt;, preservando o contexto principal. Esse desenho ajuda a tornar o uso do Claude mais governável e mais previsível.&lt;/p&gt;

&lt;h2&gt;
  
  
  O papel do &lt;code&gt;CLAUDE.md&lt;/code&gt; e da estrutura &lt;code&gt;.claude/&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Antes mesmo de falar em &lt;em&gt;spec-driven&lt;/em&gt;, vale entender a arquitetura recomendada pelo Claude Code. O arquivo &lt;code&gt;CLAUDE.md&lt;/code&gt; é carregado em toda sessão e serve para guardar &lt;strong&gt;convenções duradouras do projeto&lt;/strong&gt;: comandos de build/test/lint, stack principal, padrões de exportação, formato das APIs e outras regras “sempre válidas”. Já a pasta &lt;code&gt;.claude/&lt;/code&gt; pode armazenar &lt;em&gt;skills&lt;/em&gt;, regras por caminho, subagentes, configurações e memória adicional do agente. A recomendação explícita é: use &lt;code&gt;CLAUDE.md&lt;/code&gt; para o que vale sempre; mova o que é específico de certas tarefas para &lt;em&gt;skills&lt;/em&gt; ou regras mais localizadas.&lt;/p&gt;

&lt;p&gt;Essa separação é crucial para manter o contexto sob controle. A própria Anthropic destaca que o &lt;strong&gt;context window&lt;/strong&gt; é um recurso escasso: conforme a janela enche, o desempenho pode degradar, e o agente pode começar a perder instruções ou cometer mais erros. Por isso, um projeto bem estruturado no Claude Code tende a usar &lt;code&gt;CLAUDE.md&lt;/code&gt; como camada base, &lt;em&gt;skills&lt;/em&gt; como capacidades sob demanda e critérios de verificação claros para cada tarefa.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que significa trabalhar de forma &lt;em&gt;spec-driven&lt;/em&gt; com Claude Code
&lt;/h2&gt;

&lt;p&gt;No contexto do Claude Code, “&lt;em&gt;spec-driven&lt;/em&gt;” deve ser entendido menos como uma funcionalidade isolada e mais como uma &lt;strong&gt;disciplina de engenharia&lt;/strong&gt;. Em vez de pedir “implementa isso aí”, você começa por uma &lt;strong&gt;especificação explícita&lt;/strong&gt;: objetivo, requisitos, critérios de aceite, restrições técnicas, comandos de validação, arquivos afetados e, se possível, exemplos ou testes esperados. Essa abordagem conversa diretamente com o loop agentivo descrito pela Anthropic — reunir contexto, agir e verificar — porque fornece ao agente um norte claro para decidir o que ler, o que mudar e como provar que o trabalho foi concluído.&lt;/p&gt;

&lt;p&gt;A Anthropic reforça em suas boas práticas que a alavanca mais forte para qualidade é &lt;strong&gt;dar ao Claude um jeito de verificar o próprio trabalho&lt;/strong&gt;, incluindo testes, saídas esperadas e critérios objetivos de sucesso. Em outras palavras, uma boa especificação para Claude Code não descreve apenas “o que construir”, mas também “como saber que está certo”. Isso muda a relação com o agente: em vez de depender de inspeção manual a cada passo, você transforma a tarefa em algo mais verificável e iterável.&lt;/p&gt;

&lt;p&gt;Essa lógica aparece também nos textos da Anthropic sobre agentes de longa duração. Em trabalhos mais complexos, eles relatam ganhos ao &lt;strong&gt;decompor uma especificação de produto em lista de tarefas&lt;/strong&gt; e ao usar &lt;strong&gt;artefatos estruturados&lt;/strong&gt; para fazer a passagem de contexto entre sessões. Ou seja: o “&lt;em&gt;spec-driven&lt;/em&gt;” é, na prática, o uso de documentos e estruturas intermediárias para evitar que o agente tente fazer tudo de uma vez, perca coerência ou finalize cedo demais.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que combinar &lt;em&gt;skills&lt;/em&gt; com &lt;em&gt;spec-driven&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;A combinação é poderosa porque cada peça resolve um problema diferente. O &lt;em&gt;spec-driven&lt;/em&gt; organiza o &lt;strong&gt;trabalho corrente&lt;/strong&gt;: o que deve ser feito agora, quais critérios definem sucesso e quais restrições precisam ser respeitadas. Já as &lt;em&gt;skills&lt;/em&gt; organizam o &lt;strong&gt;conhecimento e o método recorrente&lt;/strong&gt;: como o seu time costuma quebrar requisitos em tarefas, como validar mudanças em API, como revisar segurança, como preparar uma PR ou como executar um deploy seguro.&lt;/p&gt;

&lt;p&gt;Na prática, isso significa que a especificação vira a &lt;strong&gt;fonte da verdade daquela entrega&lt;/strong&gt;, enquanto as &lt;em&gt;skills&lt;/em&gt; viram os &lt;strong&gt;procedimentos operacionais padrão&lt;/strong&gt; que o Claude aplica repetidamente. Essa separação evita dois extremos: um &lt;code&gt;CLAUDE.md&lt;/code&gt; inchado com instruções demais e prompts gigantescos reescritos a cada demanda. Também melhora a capacidade do agente de atuar em paralelo ou em subagentes, porque cada unidade de trabalho pode carregar uma &lt;em&gt;skill&lt;/em&gt; adequada sem poluir o contexto principal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estrutura recomendada para um projeto
&lt;/h2&gt;

&lt;p&gt;Uma forma madura de organizar isso é manter três camadas bem distintas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;meu-projeto/
├─ CLAUDE.md
├─ docs/
│  └─ specs/
│     ├─ auth-refresh-token.md
│     └─ billing-retry-policy.md
└─ .claude/
   ├─ skills/
   │  ├─ implement-from-spec/
   │  │  └─ SKILL.md
   │  ├─ review-against-spec/
   │  │  └─ SKILL.md
   │  └─ open-pr-with-checklist/
   │     └─ SKILL.md
   ├─ rules/
   │  └─ testing.md
   └─ settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nessa organização, o &lt;code&gt;CLAUDE.md&lt;/code&gt; guarda convenções permanentes; &lt;code&gt;docs/specs/&lt;/code&gt; concentra as especificações por funcionalidade; e &lt;code&gt;.claude/skills/&lt;/code&gt; encapsula workflows reutilizáveis. Isso segue a lógica do Claude Code para separar &lt;strong&gt;contexto persistente&lt;/strong&gt;, &lt;strong&gt;conhecimento sob demanda&lt;/strong&gt; e &lt;strong&gt;customizações do agente&lt;/strong&gt; dentro da pasta &lt;code&gt;.claude/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo de &lt;em&gt;skill&lt;/em&gt; para implementação a partir de especificação
&lt;/h2&gt;

&lt;p&gt;Abaixo está um exemplo original de &lt;em&gt;skill&lt;/em&gt; que você poderia usar para implementar uma feature a partir de uma spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;implement-from-spec&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Implementa uma funcionalidade a partir de uma especificação em docs/specs e valida com testes.&lt;/span&gt;
&lt;span class="na"&gt;disable-model-invocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;allowed-tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Grep, Glob, Edit, Write, Bash&lt;/span&gt;
&lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fork&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="s"&gt;Você vai implementar a funcionalidade descrita em $ARGUMENTS.&lt;/span&gt;

&lt;span class="na"&gt;Passos obrigatórios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;1. Ler a especificação informada.&lt;/span&gt;
&lt;span class="s"&gt;2. Identificar requisitos funcionais e não funcionais.&lt;/span&gt;
&lt;span class="s"&gt;3. Mapear arquivos impactados.&lt;/span&gt;
&lt;span class="s"&gt;4. Propor plano curto antes de editar.&lt;/span&gt;
&lt;span class="s"&gt;5. Implementar em pequenos incrementos.&lt;/span&gt;
&lt;span class="s"&gt;6. Executar testes e validações relevantes.&lt;/span&gt;
&lt;span class="s"&gt;7. Comparar resultado final com os critérios de aceite da spec.&lt;/span&gt;
&lt;span class="na"&gt;8. Gerar resumo com&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;requisitos atendidos&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pendências&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;riscos&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;testes executados&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa &lt;em&gt;skill&lt;/em&gt; traduz muito bem o espírito &lt;em&gt;spec-driven&lt;/em&gt;: ela exige leitura da especificação, transforma requisitos em plano de ação, implementa de forma incremental e fecha com verificação contra critérios de aceite. O uso de &lt;code&gt;context: fork&lt;/code&gt; também segue o padrão recomendado para tarefas mais estruturadas que se beneficiam de um subagente isolado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo de fluxo operacional
&lt;/h2&gt;

&lt;p&gt;Um fluxo de trabalho simples pode ser:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Registrar a convenção do projeto&lt;/strong&gt; em &lt;code&gt;CLAUDE.md&lt;/code&gt; (build, teste, lint, stack, padrões de PR).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Criar a spec&lt;/strong&gt; em &lt;code&gt;docs/specs/feature-x.md&lt;/code&gt;, incluindo problema, escopo, fora de escopo, critérios de aceite e validação esperada. Essa parte é uma prática de engenharia, mas ela se encaixa diretamente na recomendação de fornecer critérios de verificação claros ao Claude.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Executar uma skill&lt;/strong&gt; como &lt;code&gt;/implement-from-spec docs/specs/feature-x.md&lt;/code&gt;. Como &lt;em&gt;skills&lt;/em&gt; podem ser invocadas por slash command e até executadas em subagentes, elas funcionam como um “modo de operação” repetível.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rodar uma segunda skill de revisão&lt;/strong&gt;, por exemplo &lt;code&gt;/review-against-spec docs/specs/feature-x.md&lt;/code&gt;, para comparar a implementação final com a spec e levantar gaps. Isso reforça o princípio de verificação e fechamento por critérios objetivos.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Benefícios reais dessa abordagem
&lt;/h2&gt;

&lt;p&gt;O primeiro benefício é &lt;strong&gt;consistência&lt;/strong&gt;. Ao encapsular procedimentos em &lt;em&gt;skills&lt;/em&gt;, você reduz a variação entre sessões e entre engenheiros. O segundo é &lt;strong&gt;governança&lt;/strong&gt;: dá para controlar quem pode disparar certas ações, quais ferramentas ficam liberadas e quando uma &lt;em&gt;skill&lt;/em&gt; deve rodar em contexto isolado. O terceiro é &lt;strong&gt;eficiência de contexto&lt;/strong&gt;, já que o Claude não precisa carregar instruções detalhadas o tempo todo — basta saber que a &lt;em&gt;skill&lt;/em&gt; existe e carregá-la quando necessário.&lt;/p&gt;

&lt;p&gt;O quarto benefício é &lt;strong&gt;escalabilidade em tarefas longas&lt;/strong&gt;. As publicações da Anthropic sobre agentes de longa duração mostram que decompor o trabalho, usar artefatos estruturados e manter handoffs claros entre etapas melhora muito a coerência em sessões extensas. Esse é exatamente o tipo de ganho que o &lt;em&gt;spec-driven&lt;/em&gt; traz quando combinado com &lt;em&gt;skills&lt;/em&gt; bem definidas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limites e cuidados
&lt;/h2&gt;

&lt;p&gt;Mesmo com uma boa arquitetura, Claude Code continua sendo um agente probabilístico. A própria Anthropic destaca que contexto excessivo degrada performance e que tarefas vagas sem critérios de validação tendem a gerar saídas aparentemente boas, mas incorretas. Por isso, &lt;em&gt;skills&lt;/em&gt; não devem virar depósito de instruções gigantes, e specs não devem ser documentos prolixos sem testes ou condições de aceite objetivas.&lt;/p&gt;

&lt;p&gt;Outro cuidado é não transformar tudo em &lt;em&gt;skill&lt;/em&gt;. A documentação é clara ao diferenciar funções: &lt;code&gt;CLAUDE.md&lt;/code&gt; para convenções persistentes; &lt;em&gt;skills&lt;/em&gt; para workflows e conhecimento reutilizável; hooks para automações determinísticas; MCP para integrações externas; subagentes para isolamento e paralelismo. Escolher a abstração errada gera mais complexidade, não mais produtividade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Usar &lt;strong&gt;Claude Code&lt;/strong&gt; com &lt;strong&gt;skills&lt;/strong&gt; e uma abordagem &lt;strong&gt;spec-driven&lt;/strong&gt; é, na prática, transformar um assistente de código em um &lt;strong&gt;sistema de trabalho mais confiável&lt;/strong&gt;. As &lt;em&gt;skills&lt;/em&gt; dão forma reutilizável ao seu método; as specs dão direção concreta para a execução; &lt;code&gt;CLAUDE.md&lt;/code&gt; garante alinhamento de base; e os mecanismos de subagentes, ferramentas e validação completam o ciclo. O resultado é menos improviso, mais reprodutibilidade e maior capacidade de usar o agente em tarefas reais de engenharia de software.&lt;/p&gt;

</description>
      <category>ia</category>
      <category>dev</category>
      <category>code</category>
      <category>claude</category>
    </item>
    <item>
      <title>Multi-Selection Like VSCode in Notepad++</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Fri, 30 May 2025 01:42:48 +0000</pubDate>
      <link>https://forem.com/pinei/multi-selection-like-vscode-in-notepad-218m</link>
      <guid>https://forem.com/pinei/multi-selection-like-vscode-in-notepad-218m</guid>
      <description>&lt;p&gt;Many developers love the multi-selection feature in Visual Studio Code (VSCode), where pressing &lt;code&gt;Ctrl+D&lt;/code&gt; selects the next occurrence of the currently selected text—allowing you to edit multiple places at once. &lt;/p&gt;

&lt;p&gt;Notepad++ does not offer this natively, but with the powerful NppExec plugin and some configuration, you can achieve a very similar workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Multi-Selection Works in VSCode
&lt;/h3&gt;

&lt;p&gt;In VSCode, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select a word or text fragment.&lt;/li&gt;
&lt;li&gt;Press Ctrl+D to select the next occurrence of that text.&lt;/li&gt;
&lt;li&gt;Continue pressing Ctrl+D to add more occurrences to your selection.&lt;/li&gt;
&lt;li&gt;Edit all selected instances simultaneously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This feature is invaluable for refactoring, quick edits, or making the same change in multiple places.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Replicate Multi-Selection in Notepad++
&lt;/h3&gt;

&lt;p&gt;Notepad++ does not have this feature out-of-the-box, but you can configure it using the NppExec plugin and the Shortcut Mapper. Here’s how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: Install NppExec Plugin

&lt;ul&gt;
&lt;li&gt;Open Notepad++.&lt;/li&gt;
&lt;li&gt;Go to Plugins &amp;gt; Plugins Admin.&lt;/li&gt;
&lt;li&gt;Find and install NppExec.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you encounter installation issues, you may need admin rights or to manually copy the plugin files to the Notepad++ plugins directory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 2: Create the Multi-Selection Script

&lt;ul&gt;
&lt;li&gt;Go to Plugins &amp;gt; NppExec &amp;gt; Execute....&lt;/li&gt;
&lt;li&gt;In the command window, paste the following script:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npp_console 0
sci_sendmsg SCI_SETSEARCHFLAGS SCFIND_MATCHCASE
sci_sendmsg 2690  // SCI_TARGETWHOLEDOCUMENT
sci_sendmsg 2688  // SCI_MULTIPLESELECTADDNEXT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npp_console 0&lt;/code&gt; hides the NppExec console when running the script.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sci_sendmsg SCI_SETSEARCHFLAGS SCFIND_MATCHCASE&lt;/code&gt; sets the search to be case sensitive.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sci_sendmsg 2690&lt;/code&gt; and &lt;code&gt;sci_sendmsg 2688&lt;/code&gt; are Scintilla commands that select the next occurrence of the selected text in the whole document.&lt;/p&gt;

&lt;p&gt;Click Save..., give your script a name (e.g., &lt;code&gt;MultiSelectAddNext&lt;/code&gt;), and save.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Step 3: Add the Script to the Menu and Assign a Shortcut&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Plugins &amp;gt; NppExec &amp;gt; Advanced Options.&lt;/li&gt;
&lt;li&gt;Under "Associated Scripts", select your script and click "Add/Modify".&lt;/li&gt;
&lt;li&gt;(Optional) Check "Place to the Macros submenu" if you want quick access from the menu.&lt;/li&gt;
&lt;li&gt;Click OK and restart Notepad++ if prompted.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Step 4: Assign a Shortcut Key&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to Settings &amp;gt; Shortcut Mapper.&lt;/li&gt;
&lt;li&gt;Go to the "Plugin Commands" tab.&lt;/li&gt;
&lt;li&gt;Find your script (e.g., &lt;code&gt;MultiSelectAddNext&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Double-click the "Shortcut" column and assign your preferred shortcut (e.g., Ctrl+D).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If Ctrl+D is already used, you may need to assign a different combination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Select the text you want to find more occurrences of.&lt;/li&gt;
&lt;li&gt;Press your assigned shortcut (e.g., Ctrl+D) to select the next occurrence.&lt;/li&gt;
&lt;li&gt;Repeat to select further occurrences.&lt;/li&gt;
&lt;li&gt;Edit all selected instances at once—just like in VSCode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Troubleshooting and Tips
&lt;/h3&gt;

&lt;p&gt;If the shortcut opens the &lt;code&gt;NppExec console&lt;/code&gt;, ensure npp_console 0 is at the top of your script.&lt;/p&gt;

&lt;p&gt;If your script does not appear in the Shortcut Mapper, make sure you added it via Advanced Options in NppExec.&lt;/p&gt;

&lt;p&gt;You can customize the search flags (e.g., for case sensitivity or whole word matching) by changing the value in SCI_SETSEARCHFLAGS.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Removendo arquivos indesejáveis em um repositório Git</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Wed, 02 Apr 2025 22:57:21 +0000</pubDate>
      <link>https://forem.com/pinei/removendo-arquivos-indesejaveis-em-um-repositorio-git-386g</link>
      <guid>https://forem.com/pinei/removendo-arquivos-indesejaveis-em-um-repositorio-git-386g</guid>
      <description>&lt;p&gt;Não é incomum nos depararmos com a necessidade de remoção de arquivos indesejáveis que foram parar em algum &lt;code&gt;commit&lt;/code&gt; no seu repositório Git. Pode ser um arquivo executável sujando seu histórico, ou podem ser arquivos de dados ou de configuração com informações sensíveis.&lt;/p&gt;

&lt;p&gt;Há pouco tempo era difícil tratar este tipo de situação. Agora temos ferramentas modernas e eficientes pra nos salvar.&lt;/p&gt;

&lt;p&gt;Uma delas é o &lt;code&gt;git-filter-repo&lt;/code&gt;. Uma ferramenta de linha de comando para reconstrução do repositório baseada em filtro.&lt;/p&gt;

&lt;p&gt;Para instalar podemos usar o &lt;code&gt;pip&lt;/code&gt;, um gerenciador de pacotes do Python que é ferramenta cada vez mais presente nos ambientes de desenvolvimento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install git-filter-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;git-filter-repo&lt;/code&gt; trabalha com um repositório limpo, de preferência recém clonado. É arriscado usar na sua pasta de trabalho pois ele pode fazer um &lt;code&gt;reset&lt;/code&gt; sem cerimônia, e arquivos de trabalho importantes serão perdidos.&lt;/p&gt;

&lt;p&gt;Faça um clone ou uma cópia limpa do repositório.&lt;/p&gt;

&lt;p&gt;Na pasta do clone, supondo que você queira eliminar todos os arquivos &lt;code&gt;.exe&lt;/code&gt;, dispare o comando &lt;code&gt;git filter-repo&lt;/code&gt; com o filtro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git filter-repo --path-glob '*.exe' --invert-paths
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A ferramenta vai fazer o "trabalho sujo" e deixar o repositório brilhando. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O &lt;code&gt;git filter-repo&lt;/code&gt; analisará todo o histórico e removerá as referências ao(s) arquivo(s) especificado(s). Ele também faz uma limpeza automática (como &lt;code&gt;git gc&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NOTICE: Removing 'origin' remote; see 'Why is my origin removed?'
        in the manual if you want to push back there.
        (was ...)
Parsed 43 commits
New history written in 0.43 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adicione ao &lt;code&gt;.gitignore&lt;/code&gt; para prevenir futuros commits.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Crie ou edite o arquivo .gitignore na raiz do seu repositório e adicione uma linha &lt;code&gt;*.exe&lt;/code&gt; para ignorar os arquivos.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add .gitignore
git commit -m "Adiciona .exe ao gitignore"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Envie as alterações para o repositório remoto. Como você reescreveu o histórico, um &lt;code&gt;git push&lt;/code&gt; normal provavelmente não vai rolar. Você precisará forçar o push.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Forçar o push (&lt;code&gt;--force&lt;/code&gt; ou &lt;code&gt;--force-with-lease&lt;/code&gt;) sobrescreve o histórico no repositório remoto. Avise todos os colaboradores antes de fazer isso, pois eles precisarão atualizar seus clones locais de maneira especial (geralmente fazendo &lt;code&gt;fetch&lt;/code&gt; e &lt;code&gt;reset&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push origin nome-da-sua-branch --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E é isso.&lt;/p&gt;

&lt;p&gt;Lembre-se sempre do backup e da comunicação com a equipe ao reescrever o histórico.&lt;/p&gt;

</description>
      <category>git</category>
      <category>commit</category>
      <category>repo</category>
      <category>filter</category>
    </item>
    <item>
      <title>Reformatting dictionaries in Python</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Wed, 12 Feb 2025 23:28:24 +0000</pubDate>
      <link>https://forem.com/pinei/reformatando-dicionarios-em-python-58dc</link>
      <guid>https://forem.com/pinei/reformatando-dicionarios-em-python-58dc</guid>
      <description>&lt;p&gt;Today we'll explore a common problem when working with lists of dictionaries in Python: the need to filter those dictionaries based on a specific set of keys. We'll present two concise and efficient solutions, utilizing powerful features of the language.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Imagine you have a list of dictionaries, where each dictionary represents a set of parameters. In some situations, you need to extract only the attributes (key-value pairs) that correspond to a subset of keys.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2020-01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2020-02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2020-02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2020-03&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;filtered_parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;filter_dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filtered_parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Expected output:
# [{'start': '2020-01', 'end': '2020-02'},
#  {'start': '2020-02', 'end': '2020-03'}]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our goal is to get a new list of dictionaries, containing only the "start" and "end" attributes from each original dictionary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 1: Traditional iteration with if
&lt;/h3&gt;

&lt;p&gt;The first approach uses a for loop to iterate over the list of dictionaries and another nested for loop to iterate over the desired keys. Inside the inner loop, we check if the key exists in the current dictionary and, if so, add the key-value pair to the new dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filter_dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&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;dictionary&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;new_dict&lt;/span&gt; &lt;span class="o"&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;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;keys&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;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;new_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_dict&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;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Solution 2: List Comprehension for the rescue
&lt;/h3&gt;

&lt;p&gt;Python offers a powerful feature called list comprehension, which allows you to create lists and dictionaries concisely and expressively. We can use list comprehension to implement dictionary filtering in virtually a single line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filter_dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&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="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&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;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dictionary&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;dictionary&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is more compact and, for many developers, more readable than the version with nested loops.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparing approaches
&lt;/h3&gt;

&lt;p&gt;Both solutions are efficient and produce the same result. The choice between them is a matter of personal preference. Some may find the list comprehension version more elegant and concise, while others may prefer the clarity of traditional iteration.&lt;/p&gt;

&lt;p&gt;Tip: When working with lists and dictionaries, prioritize the use of list comprehension to write cleaner and more precise code.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>DeepSeek, Efficiency, and Big Tech’s Response</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Tue, 04 Feb 2025 04:40:21 +0000</pubDate>
      <link>https://forem.com/pinei/deepseek-efficiency-and-big-techs-response-3ga9</link>
      <guid>https://forem.com/pinei/deepseek-efficiency-and-big-techs-response-3ga9</guid>
      <description>&lt;p&gt;DeepSeek, a rising star in the Chinese AI landscape, has quickly become one of the most downloaded AI apps, sparking discussions about the future of AI investment and resource allocation. What sets DeepSeek apart is its ability to develop a competitive AI model at a fraction of the cost of dominant U.S. models, which often require hundreds of billions of dollars in investment. While the exact cost of DeepSeek’s development is debated — likely higher than the reported $6 million — it remains a testament to the efficiency and innovation achievable under constraints. This efficiency is particularly evident in DeepSeek’s latest model, R1, which many see as a direct response to OpenAI’s o1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/deepseek-ai/DeepSeek-R1" rel="noopener noreferrer"&gt;deepseek-ai/DeepSeek-R1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;he development of Deepseek underscores how limitations can drive technological breakthroughs. China’s restrictions on advanced GPUs forced Deepseek to focus on software optimization, resulting in a more efficient AI model. This aligns with a broader principle in technology innovation: initial phases of hype and overspending are often followed by periods of refinement and efficiency, especially when resources are scarce.&lt;/p&gt;

&lt;p&gt;DeepSeek’s success demonstrates that constraints can foster creativity and lead to solutions that challenge the status quo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jevons Paradox and its potential implications for the AI industry
&lt;/h3&gt;

&lt;p&gt;The concept of Jevons Paradox — where increased efficiency leads to greater resource consumption — may hold significant implications for the AI industry. Microsoft CEO Satya Nadella has suggested that this paradox applies to AI, arguing that as models like DeepSeek’s R1 become more efficient and accessible, their use will skyrocket, turning AI into a commodity. This could lead to a surge in AI applications across industries, further accelerating innovation and adoption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Market Reaction
&lt;/h3&gt;

&lt;p&gt;The emergence of DeepSeek has sent ripples through the tech industry, with major tech and chip companies experiencing a downturn. This shift reflects a growing realization that AI innovation may no longer be as heavily reliant on hardware as previously thought. While this poses challenges for companies heavily invested in hardware, it is ultimately a positive development for the long-term growth of AI, making the technology more accessible and affordable.&lt;/p&gt;

&lt;p&gt;Some investors are calling DeepSeek’s rise a “Sputnik moment” for AI, signaling that the U.S. no longer holds a monopoly on AI innovation. DeepSeek has proven that world-class AI models can be developed outside the U.S., even under significant constraints. This shift is likely to encourage greater global participation in AI development, with the open-source community playing a pivotal role in further optimizing and democratizing AI technology.&lt;/p&gt;

&lt;p&gt;As the market digests DeepSeek’s impact, all eyes are on upcoming quarterly updates and management calls from tech giants like ASML, Meta, Microsoft, Tesla, and Apple. Analysts will be keen to understand how these companies plan to balance efficiency with their past capital investments in light of DeepSeek’s success. The pressure is on for these firms to demonstrate adaptability and forward-thinking strategies in an increasingly competitive AI landscape.&lt;/p&gt;

&lt;h3&gt;
  
  
  DeepSeek R1 Model
&lt;/h3&gt;

&lt;p&gt;DeepSeek’s R1 model is a prime example of efficiency-driven AI development. Designed to require only a fraction of the compute resources compared to other models, R1 was reportedly developed on a budget of $5.6 million, far less than the $100 million spent on training ChatGPT-4. The model emphasizes software optimization and leverages constraints, such as limited access to advanced GPUs, to achieve superior performance.&lt;/p&gt;

&lt;p&gt;R1’s architecture is both innovative and practical. With 671 billion parameters, it activates only 37 billion during use, making it highly efficient. DeepSeek also offers smaller distilled models, ranging from 1.5B to 70B parameters, based on Qwen and Llama architectures. These models are designed to deliver powerful reasoning capabilities, self-verification, and the ability to generate long chains of thought (CoTs), demonstrating that the reasoning patterns of larger models can be distilled into smaller, more accessible versions.&lt;/p&gt;

&lt;p&gt;DeepSeek’s commitment to open-source development is another key factor in its success. The company has made R1-Zero, R1, and six dense models distilled from R1 available to the public, supporting commercial use, modifications, and derivative works. This open approach not only fosters collaboration but also accelerates the pace of innovation within the AI community.&lt;/p&gt;

&lt;p&gt;DeepSeek’s models have been rigorously evaluated across a range of tasks, including math, coding, and language understanding. Metrics such as MMLU (Pass@1), DROP (F1), LiveCodeBench (Pass@1-COT), and Codeforces (Rating) highlight the model’s strong performance, particularly in reasoning and problem-solving tasks. These results position DeepSeek as a formidable competitor to established models like OpenAI’s o1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11lekz0d2xyrw1wpqznf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11lekz0d2xyrw1wpqznf.png" alt="Benchmark" width="700" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DeepSeek’s rise marks a significant shift in the AI landscape, challenging traditional notions of resource dependency and innovation. By turning constraints into opportunities, DeepSseek has not only developed a highly efficient AI model but also sparked a broader conversation about the future of AI development. As the industry continues to evolve, DeepSeek’s approach — rooted in efficiency, open collaboration, and adaptability — may well set the standard for the next generation of AI innovation.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Git: recreating the history</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Sat, 14 Oct 2023 20:49:33 +0000</pubDate>
      <link>https://forem.com/pinei/git-recreating-history-7d8</link>
      <guid>https://forem.com/pinei/git-recreating-history-7d8</guid>
      <description>&lt;p&gt;Why you might want to reset the history of your Git repository and redefine the files that will be versioned?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Reduce Repository Size: Over time, a repository can accumulate a large history with numerous commits, branches, and tagged releases. This can make cloning the repository very slow, especially for new team members. Resetting the history can help shrink the repository's size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sensitive Data Removal: If sensitive data like passwords or API keys have been committed to the repository, it's crucial to remove that information. While you can remove this data in a new commit, the sensitive data will still exist in the repository's history. A hard reset is often the safest way to completely remove this data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simplify History: A complex and messy commit history can make it difficult for team members to understand the evolution of a project. Resetting the history can simplify it by removing redundant or meaningless commits, making it easier to understand and maintain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change of Project Scope: Sometimes projects pivot or change direction. In such cases, old files, dependencies, and even codebases may no longer be relevant. Resetting the history allows you to start anew while keeping the most relevant parts intact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Licensing or Ownership Changes: In case the project undergoes changes in licensing or ownership, you may need to remove specific parts of the history to comply with legal requirements. This can involve removing commits from contributors who have not agreed to new terms, or removing code that cannot be licensed under the new terms.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a step-by-step guide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1. Create a new "orphan" branch that does not inherit history.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;--orphan&lt;/span&gt; new_branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;2. Remove all files from the Git index (staging area).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This removes files only from the index, not from the file system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;3. Add the files you wish to version. Take the opportunity to set up &lt;code&gt;.gitignore&lt;/code&gt;. Commit these changes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit with selected files"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;4. Delete the old main branch.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch &lt;span class="nt"&gt;-D&lt;/span&gt; main  &lt;span class="c"&gt;# replace "main" with the name of your main branch, if different&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;5. Rename the new branch to be the new main branch.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch &lt;span class="nt"&gt;-m&lt;/span&gt; main  &lt;span class="c"&gt;# again, replace "main" if necessary&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;6. Perform a "force push" to the remote repository.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-f&lt;/span&gt; origin main  &lt;span class="c"&gt;# replace "main" and "origin" as needed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These actions are irreversible on the remote repository and can cause issues for other collaborators who are working on the same repository. Measures need to be taken to synchronize their local copies with the new history.&lt;/p&gt;

&lt;p&gt;By following these steps, you will create a new main branch with a new set of versioned files, discarding the previous history.&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Running PySpark in JupyterLab on a Raspberry Pi</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Sun, 01 Oct 2023 23:44:42 +0000</pubDate>
      <link>https://forem.com/pinei/running-pyspark-in-jupyterlab-on-a-raspberry-pi-1293</link>
      <guid>https://forem.com/pinei/running-pyspark-in-jupyterlab-on-a-raspberry-pi-1293</guid>
      <description>&lt;p&gt;While researching materials for installing a JupyterLab instance with Spark support (via PySpark), I noticed a lot of outdated content. That was until I came across an up-to-date Docker image provided by the Jupyter Docker Stacks project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jupyter-docker-stacks.readthedocs.io/en/latest/using/specifics.html#apache-spark" rel="noopener noreferrer"&gt;https://jupyter-docker-stacks.readthedocs.io/en/latest/using/specifics.html#apache-spark&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python and Java have good support for ARM architecture, so we can assume that any framework developed on these platforms will run well on a Raspberry Pi. Then, I just ran the Docker command to start the environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --rm -p 8888:8888 jupyter/pyspark-notebook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It couldn't be easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdonwparpl0yheezmgpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdonwparpl0yheezmgpx.png" alt="Jupyter Lab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Checking CPU and memory&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx56vq3butijhll75935.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx56vq3butijhll75935.png" alt="!lscpu and !free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try a simple code to check the availability of the PySpark and SQL API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyspark.sql&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SparkSession&lt;/span&gt;

&lt;span class="n"&gt;spark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;SparkSession&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Python Spark SQL basic example&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spark.executor.memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2g&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spark.executor.cores&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spark.eventLog.enabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spark.sql.shuffle.partitions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spark.serializer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;org.apache.spark.serializer.KryoSerializer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Got a SparkSession-in-memory&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Version: v3.5.0&lt;/li&gt;
&lt;li&gt;Master: local[*]&lt;/li&gt;
&lt;li&gt;AppName: Python Spark SQL basic example&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can setup a dataframe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyspark.sql.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StructType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StructField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FloatType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BooleanType&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyspark.sql.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DoubleType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IntegerType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringType&lt;/span&gt;

&lt;span class="c1"&gt;# Setup the Schema
&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StructType&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
&lt;span class="nc"&gt;StructField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IntegerType&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nc"&gt;StructField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringType&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nc"&gt;StructField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Browser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringType&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nc"&gt;StructField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringType&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Add Data
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;([(&lt;/span&gt;&lt;span class="mi"&gt;1580&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Barry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FireFox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Windows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5820&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sam&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MS Edge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Linux&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2340&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Harry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Vivaldi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Windows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7860&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Albert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chrome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Windows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1123&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;May&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Safari&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;macOS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Setup the Data Frame
&lt;/span&gt;&lt;span class="n"&gt;user_data_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user_data_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------+--------+-------+-------+
|User ID|Username|Browser|     OS|
+-------+--------+-------+-------+
|   1580|   Barry|FireFox|Windows|
|   5820|     Sam|MS Edge|  Linux|
|   2340|   Harry|Vivaldi|Windows|
|   7860|  Albert| Chrome|Windows|
|   1123|     May| Safari|  macOS|
+-------+--------+-------+-------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can save this dataframe to a physical table in a new database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;spark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CREATE DATABASE raspland&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user_data_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveAsTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;raspland.user_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then run SQL commands over the table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;spark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM raspland.user_data WHERE OS = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Linux&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------+--------+-------+-----+
|User ID|Username|Browser|   OS|
+-------+--------+-------+-----+
|   5820|     Sam|MS Edge|Linux|
+-------+--------+-------+-----+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By accessing the Terminal, we can check the Parquet files that store the data of our created table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(base) jovyan@0e1d1463f0b0:~/spark-warehouse/raspland.db/user_data$ ls

part-00000-963849eb-9b82-4bf7-ab1c-f71800914e15-c000.snappy.parquet
part-00001-963849eb-9b82-4bf7-ab1c-f71800914e15-c000.snappy.parquet
part-00002-963849eb-9b82-4bf7-ab1c-f71800914e15-c000.snappy.parquet
part-00003-963849eb-9b82-4bf7-ab1c-f71800914e15-c000.snappy.parquet
_SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the &lt;code&gt;jupyterlab-sql-editor&lt;/code&gt; extension to get enhanced functionalities for SQL execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frissjmc0cwzpd70a1wpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frissjmc0cwzpd70a1wpc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a post to learn more about the extension:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/jupyterlab-sql-cell-editor-e6ac865b42df" rel="noopener noreferrer"&gt;https://towardsdatascience.com/jupyterlab-sql-cell-editor-e6ac865b42df&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to run 2 commands in the Terminal to install server prerequisites.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install jupyterlab-lsp jupyterlab-sql-editor
sudo npm install -g sql-language-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Load the extension in the notebook ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%load_ext jupyterlab_sql_editor.ipython_magic.sparksql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and SparkSQL cells will be enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsecgxvrq9lntmy2ldg9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsecgxvrq9lntmy2ldg9s.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Metastore
&lt;/h3&gt;

&lt;p&gt;Spark should be using a Hive metastore to manage databases and tables. We will talk about Hive later. Until now, our data has been physically persisted in Parquet files, while our metadata remains in memory.&lt;/p&gt;

&lt;p&gt;We need to enable Hive Support to persist our metadata. So let's delete our data, recreate our Spark session, and run the sample again.&lt;/p&gt;

&lt;p&gt;In the Terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm -rf spark-warehouse/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the code in the notebook to enable Hive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyspark.sql&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SparkSession&lt;/span&gt;

&lt;span class="n"&gt;spark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;SparkSession&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Python Spark SQL basic example&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableHiveSupport&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running our database creation script, certain files and folders appear in the file explorer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ls0hhefh9au1c5tsjhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ls0hhefh9au1c5tsjhp.png" alt="metastore_db folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;spark-warehouse&lt;/code&gt; houses our Parquet files, &lt;code&gt;metastore_db&lt;/code&gt; serves as a Derby repository to store our database and table definitions.&lt;/p&gt;

&lt;p&gt;Derby is a lightweight relational database management system (RDBMS) implemented in Java. It is often used as a local, embedded metastore for Spark's SQL component when running in standalone mode.&lt;/p&gt;

&lt;p&gt;Hive is a data warehousing and SQL query engine for Hadoop, originally developed by Facebook. It allows you to query big data in a distributed storage architecture like Hadoop's HDFS using SQL-like syntax. Hive's architecture includes a metadata repository stored in an RDBMS, which is often referred to as the Hive Metastore.&lt;/p&gt;

&lt;p&gt;The standalone installation of Spark does not inherently include Hive, but it has built-in support for connecting to a Hive metastore if you have one set up separately.&lt;/p&gt;

&lt;p&gt;Thank you for reading. Let me know in the comments what else you might be interested in to complement this article.&lt;/p&gt;

</description>
      <category>jupyter</category>
      <category>pyspark</category>
      <category>docker</category>
      <category>raspberrypi</category>
    </item>
    <item>
      <title>A comparison of SageMaker and Databricks for machine learning</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Fri, 21 Jul 2023 18:08:05 +0000</pubDate>
      <link>https://forem.com/pinei/a-comparison-of-sagemaker-and-databricks-for-machine-learning-2pfj</link>
      <guid>https://forem.com/pinei/a-comparison-of-sagemaker-and-databricks-for-machine-learning-2pfj</guid>
      <description>&lt;h3&gt;
  
  
  SageMaker
&lt;/h3&gt;

&lt;p&gt;Amazon SageMaker is a fully managed service that provides an end-to-end machine learning (ML) platform. It includes a variety of features that help you build, train, deploy, and monitor ML models.&lt;/p&gt;

&lt;p&gt;Some of the key features of Amazon SageMaker include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A wide range of pre-trained models: Amazon SageMaker provides a wide range of pre-trained models that you can use to get started with ML quickly. These models are trained on a variety of datasets, so you can find a model that is relevant to your application.&lt;/li&gt;
&lt;li&gt;A variety of algorithms: Amazon SageMaker provides a variety of algorithms that you can use to train your own ML models. These algorithms include linear regression, logistic regression, decision trees, random forests, and support vector machines.&lt;/li&gt;
&lt;li&gt;A variety of deployment options: Amazon SageMaker provides a variety of deployment options for your ML models. You can deploy your models to Amazon SageMaker hosting services, Amazon Elastic Container Service (ECS), or Amazon Elastic Beanstalk.&lt;/li&gt;
&lt;li&gt;A variety of monitoring tools: Amazon SageMaker provides a variety of monitoring tools that you can use to track the performance of your ML models. These tools include Amazon CloudWatch, Amazon SageMaker Model Monitor, and Amazon SageMaker Anomaly Detection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8gvOSTbi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://th.bing.com/th/id/R.7ec475c03ac0c84707b1d2d0a733b5fe%3Frik%3Dk45xrVdNsVh%252f6Q%26pid%3DImgRaw%26r%3D0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8gvOSTbi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://th.bing.com/th/id/R.7ec475c03ac0c84707b1d2d0a733b5fe%3Frik%3Dk45xrVdNsVh%252f6Q%26pid%3DImgRaw%26r%3D0" alt="SageMaker Quick Start Solutions" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/sagemaker/latest/dg/studio-jumpstart.html"&gt;SageMaker JumpStart&lt;/a&gt; provides a Python SDK with pretrained, open-source models for a wide range of problem types.&lt;/p&gt;

&lt;p&gt;Here are some of the benefits of using Amazon SageMaker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced development time: Amazon SageMaker can help you reduce the development time for your ML models. You can focus on building your models, not on provisioning and managing infrastructure.&lt;/li&gt;
&lt;li&gt;Improved accuracy: Amazon SageMaker can help you improve the accuracy of your ML models. It provides a variety of pre-trained models that you can use as a starting point. You can also use Amazon SageMaker's algorithms to train your own models.&lt;/li&gt;
&lt;li&gt;Increased scalability: Amazon SageMaker can automatically scale your models up or down based on demand. This can help you save money on infrastructure costs.&lt;/li&gt;
&lt;li&gt;Improved security: The service provides a variety of features that can help you protect your models from unauthorized access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Databricks
&lt;/h3&gt;

&lt;p&gt;Databricks is a cloud-based platform that offers a unified environment for data engineering, data science, and machine learning, self-identifying as a Lakehouse platform. It is built on top of Apache Spark, which is a popular open-source distributed computing framework. The service has grown to support the 3 major public clouds (AWS, Azure, GCP) in several regions around the world.&lt;/p&gt;

&lt;p&gt;In the context of ML, Databricks can be used to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build and train ML models: Databricks provides a variety of tools and libraries that can be used to build and train ML models. These tools include the MLflow tracking library, which can be used to track the performance of ML models, and the AutoML functionality, which can be used to automatically train and tune ML models.&lt;/li&gt;
&lt;li&gt;Deploy ML models: Once an ML model has been trained, it can be deployed to production using the platform. Databricks provides a variety of deployment options, including on-premises deployments and cloud-based deployments.&lt;/li&gt;
&lt;li&gt;Monitor ML models: Once an ML model has been deployed, it can be monitored using Databricks. Databricks provides a variety of monitoring tools that can be used to track the performance of ML models, such as the MLflow tracking library and the Databricks Monitoring dashboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some of the benefits of using Databricks for ML:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ease of use: Databricks has a user-friendly platform that is easy to learn and use. This makes it a good choice for organizations that are new to ML.&lt;/li&gt;
&lt;li&gt;Scalability: Databricks is a scalable platform that can be used to handle large datasets and complex ML models. This makes it a good choice for organizations that need to scale their ML workloads.&lt;/li&gt;
&lt;li&gt;Integration with other tools: The platform integrates with a variety of tools for data sources, BI, development and ETL. This makes it easy to use Databricks with other tools that you are already using.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Differences in the context of ML
&lt;/h3&gt;

&lt;p&gt;Amazon SageMaker and Databricks are both popular cloud-based ML platforms, but they have different strengths and weaknesses.&lt;/p&gt;

&lt;p&gt;Amazon SageMaker is a fully managed platform that provides an end-to-end ML solution. It includes a wide range of features for building, training, deploying, and monitoring ML models. SageMaker is a good choice for organizations that want a turnkey solution that they don't have to manage themselves.&lt;/p&gt;

&lt;p&gt;Databricks is a more open platform that gives users more control over their ML infrastructure. It includes a wide range of features for data engineering, data science, and ML. It is a good choice for organizations that want a more flexible platform that they can customize to their specific needs.&lt;/p&gt;

&lt;p&gt;Here is a table that summarizes the main differences between SageMaker and Databricks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Amazon SageMaker&lt;/th&gt;
&lt;th&gt;Databricks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Managed vs. self-managed&lt;/td&gt;
&lt;td&gt;Fully managed&lt;/td&gt;
&lt;td&gt;Self-managed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Features&lt;/td&gt;
&lt;td&gt;Wide range of features for building, training, deploying, and monitoring ML models&lt;/td&gt;
&lt;td&gt;Wide range of features for data engineering, data science, and ML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;More expensive&lt;/td&gt;
&lt;td&gt;Less expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The best platform for you will depend on your specific needs and requirements. If you are looking for a turnkey solution that you don't have to manage yourself, then Amazon SageMaker is a good choice. If you want a more flexible platform that you can customize to your specific needs, then Databricks is a good choice.&lt;/p&gt;

&lt;p&gt;Some additional considerations that may help you decide which platform is right for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your team's experience with ML: If your team is new to ML, then Amazon SageMaker may be a good choice because it provides a more guided experience. If your team has more experience with ML, then Databricks may be a good choice because it gives you more flexibility.&lt;/li&gt;
&lt;li&gt;The size of your dataset: If you have a large dataset, then Amazon SageMaker may be a better choice because it can scale fast to handle larger datasets. Databricks is more cost-effective for smaller datasets.&lt;/li&gt;
&lt;li&gt;Your specific requirements: If you have specific requirements, such as the need for a particular algorithm or the need to integrate with a specific third-party tool, then you will need to compare the features of Amazon SageMaker and Databricks to see which platform meets your needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Storage and data access
&lt;/h3&gt;

&lt;p&gt;Both Databricks and SageMaker offer a variety of options for storing and accessing datasets for ML activity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Databricks&lt;/strong&gt; offers these main options for storing datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Simple Storage Service (S3):&lt;/strong&gt; S3 is a highly scalable and durable object storage service. Databricks makes it easy to store datasets in S3 and to access them from Databricks notebooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databricks File System (DBFS):&lt;/strong&gt; DBFS is a distributed file system that is built on top of S3. DBFS offers a number of advantages over S3, such as the ability to store lineage information and to track changes to datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Data Lake Storage:&lt;/strong&gt; Databricks also supports Azure Data Lake Storage, which is a cloud-based file storage service from Microsoft.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Main &lt;strong&gt;SageMaker&lt;/strong&gt; options for storing datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Simple Storage Service (S3):&lt;/strong&gt; S3 is also a popular option for storing datasets in SageMaker. SageMaker makes it easy to store datasets in S3 and to access them from SageMaker notebooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Relational Database Service (RDS):&lt;/strong&gt; RDS is a fully managed relational database service that can be used to store datasets for ML activity. SageMaker makes it easy to create and connect to RDS databases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Redshift:&lt;/strong&gt; Redshift is a data warehouse service that can be used to store large datasets for ML activity. SageMaker makes it easy to create and connect to Redshift clusters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In terms of access, both Databricks and SageMaker offer a variety of ways to access datasets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Databricks&lt;/strong&gt; offers the following ways to access datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Notebooks:&lt;/strong&gt; Databricks notebooks allow you to access datasets from within a "Jupyter-like" notebook environment. This is a convenient way to explore and analyze datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL:&lt;/strong&gt; Databricks also supports SQL, so you can access datasets using SQL queries. This can be useful for working with large datasets or for integrating with other applications that use SQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python APIs:&lt;/strong&gt; Databricks also offers Python APIs that you can use to access datasets. This can be useful for automating tasks or for integrating with other applications that use Python.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SageMaker&lt;/strong&gt; offers the following ways to access datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jupyter notebooks:&lt;/strong&gt; SageMaker also allow you to access datasets from within a Jupyter notebook environment. This is a convenient way to explore and analyze datasets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python APIs:&lt;/strong&gt; SageMaker also offers Python APIs that you can use to access datasets. This can be useful for automating tasks or for integrating with other applications that use Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SageMaker Studio:&lt;/strong&gt; SageMaker Studio is a web-based IDE that allows you to access datasets and to run ML experiments. This can be a convenient way to work with datasets if you are not familiar with Jupyter notebooks or Python.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, the best way to store and access datasets for ML activity will depend on your specific needs and requirements.&lt;/p&gt;

</description>
      <category>databricks</category>
      <category>sagemaker</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Free Oracle Database (How to)</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Wed, 02 Sep 2020 05:31:30 +0000</pubDate>
      <link>https://forem.com/pinei/free-oracle-database-how-to-10hb</link>
      <guid>https://forem.com/pinei/free-oracle-database-how-to-10hb</guid>
      <description>&lt;p&gt;This article is a simple guide to getting started with 2 database models in the Oracle Cloud using the &lt;code&gt;Always Free Tier&lt;/code&gt; program.&lt;/p&gt;

&lt;p&gt;I don't work for Oracle but I have worked with Oracle tools &lt;code&gt;on premises&lt;/code&gt; for years. So it's time to check what Oracle Cloud has to offer, at least in terms of database. And no more &lt;code&gt;Oracle XE&lt;/code&gt; in the local machine 🎆 .&lt;/p&gt;

&lt;p&gt;You will need a credit card to open an account with Oracle Cloud, but the samples we are going to create are cost free.&lt;/p&gt;

&lt;p&gt;I already created an account so I will not show how to do it here. So we can jump to the &lt;a href="https://www.oracle.com/cloud/sign-in.html"&gt;console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oY4ja3zO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vwsdnd00z5zf0qxhb6l9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oY4ja3zO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vwsdnd00z5zf0qxhb6l9.png" alt="Alt Text" width="659" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can check in the console below, at the red mark, a 200 USD value trial are offered to new users for 30 days free. Be aware of the end of this period to not be surprised with the credit card later in case you keep some activated resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jg9yBLzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/z5tawhtn4z473qdznx29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jg9yBLzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/z5tawhtn4z473qdznx29.png" alt="Alt Text" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The green mark (any button) send us to the &lt;code&gt;Create Autonomous Database&lt;/code&gt; screen.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oracle Cloud Infrastructure's Autonomous Database is a fully managed, preconfigured database environment with two workload types available, Autonomous Transaction Processing and Autonomous Data Warehouse.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After setting the basic name and display name of the database, we can choose the workload type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KrZZ7OrO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/02pmzwxwuvr2xvyurzsc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KrZZ7OrO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/02pmzwxwuvr2xvyurzsc.png" alt="Alt Text" width="609" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Transactional Database and Data Warehouse are both systems that store data. But they serve very different purposes. (&lt;a href="https://panoply.io/data-warehouse-guide/the-difference-between-a-database-and-a-data-warehouse/"&gt;The Difference Between a Data Warehouse and a Database&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;JSON storage isn't available for the Always Free suite at this time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Autonomous Database can be used without charge as part of Oracle Cloud Infrastructure's suite of Always Free resources. Users have access to two Always Free instances of Autonomous Database. Always Free Autonomous Databases have a fixed 8 GB of memory, 20 GB of storage, 1 OCPU, and can be configured for either Autonomous Transaction Processing or Autonomous Data Warehouse workloads.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we can create a database for &lt;code&gt;Transaction Processing&lt;/code&gt; and another for &lt;code&gt;Data Warehouse&lt;/code&gt; as named below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Display Name&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Oracle Data Warehouse 20 GB 19c Shared Infrastructure&lt;/td&gt;
&lt;td&gt;DBWH20GB19cSHR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle Transaction Processing 20 GB 19c Shared Infrastructure&lt;/td&gt;
&lt;td&gt;DBTP20GB19cSHR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each database will have an ADMIN (default) user. Let's assume that we will use the database name as the password. 🤪&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sz09WjTp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cskskytlktfgw73883dp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sz09WjTp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cskskytlktfgw73883dp.png" alt="Alt Text" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our databases are ready. Keep in mind that they will be automatically stopped if not used for 7 days.&lt;/p&gt;

&lt;h1&gt;
  
  
  Connecting to the databases
&lt;/h1&gt;

&lt;p&gt;Oracle offers some tools to visualize and administer our databases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--09FLEWar--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/jjtga3mevy6o1f9wpbrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--09FLEWar--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/jjtga3mevy6o1f9wpbrg.png" alt="Alt Text" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn't test any of these tools yet. In general I prefer to use a local database tool. And I think &lt;a href="https://dbeaver.io/"&gt;DBeaver&lt;/a&gt; is the best free tool available for relational database managers. All we need is a JDBC driver and a way to connect to the database wherever it be.&lt;/p&gt;

&lt;p&gt;The Oracle Autonomous Databases mandates a secure connection. For this connection type, Java applications that use a &lt;code&gt;JDBC Thin driver&lt;/code&gt; require either &lt;code&gt;Oracle Wallet&lt;/code&gt; or &lt;code&gt;Java KeyStore (JKS)&lt;/code&gt;. (&lt;a href="https://docs.oracle.com/en/cloud/paas/autonomous-data-warehouse-cloud/user/connect-jdbc-thin-wallet.html#GUID-5ED3C08C-1A84-4E5A-B07A-A5114951AA9E"&gt;JDBC Thin Connections and Wallets&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If you don't understand those methods, it's not a problem. We will use &lt;code&gt;Oracle Wallet&lt;/code&gt; method in this article and you are going to see it's simple.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oracle Wallet provides a simple and easy method to manage database credentials across multiple domains. It allows you to update database credentials by updating the Wallet instead of having to change individual datasource definitions. This is accomplished by using a database connection string in the datasource definition that is resolved by an entry in the wallet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The wallet and keystore files are included in the client credentials .zip file that is available by clicking &lt;code&gt;DB Connection&lt;/code&gt; on the Oracle Cloud Infrastructure console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TiKnOxnF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/o08rar8fumet8tmoemu0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TiKnOxnF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/o08rar8fumet8tmoemu0.png" alt="Alt Text" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;code&gt;Regional Wallet&lt;/code&gt; to get the credentials for both databases in the same .zip.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T0YyUVHR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/gr368wavta592st6cs9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T0YyUVHR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/gr368wavta592st6cs9g.png" alt="Alt Text" width="603" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need a password for the wallet. I will use &lt;code&gt;myWallet1&lt;/code&gt; for this sample. This will be the &lt;code&gt;keyStore&lt;/code&gt; and &lt;code&gt;truststore&lt;/code&gt; password.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E9DrBiKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vqca7hhz9ihj2cju5oie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E9DrBiKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/vqca7hhz9ihj2cju5oie.png" alt="Alt Text" width="602" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like that the .zip includes some Oracle configuration files and some binary files for SSL certificates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--APNNJ7VZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/zrrnk1pzmcqs6etm9cuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--APNNJ7VZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/zrrnk1pzmcqs6etm9cuw.png" alt="Alt Text" width="300" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Files&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Oracle Wallet&lt;/td&gt;
&lt;td&gt;ewallet.sso, ewallet.p12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java KeyStore (JKS)&lt;/td&gt;
&lt;td&gt;truststore.jks, keystore.jks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Despite the .zip filename, the &lt;code&gt;tnsnames.ora&lt;/code&gt; includes connection strings for both databases, as we selected a Regional Wallet for download. For each database we have three or five database service names like (for instance) &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, and &lt;code&gt;low&lt;/code&gt;. The predefined service names provides different levels of performance and concurrency for Autonomous Databases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dbtp20gb19cshr_high = (description= ... )
dbtp20gb19cshr_low = (description= ... )
dbtp20gb19cshr_medium = (description= ... )
dbtp20gb19cshr_tp = (description= ... )
dbtp20gb19cshr_tpurgent = (description= ... )

dbwh20gb19cshr_high = (description= ... )
dbwh20gb19cshr_low = (description= ... )
dbwh20gb19cshr_medium = (description= ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use any service name to test our connection, but each one may serve for a different purpose in a real application as you can see in the documentation (links below).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Documentation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.oracle.com/en/cloud/paas/autonomous-data-warehouse-cloud/user/connect-predefined.html#GUID-9747539B-FD46-44F1-8FF8-F5AC650F15BE"&gt;Predefined Database Service Names for Autonomous Data Warehouse&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.oracle.com/en/cloud/paas/atp-cloud/atpug/connect-predefined.html#GUID-9747539B-FD46-44F1-8FF8-F5AC650F15BE"&gt;Predefined Database Service Names for Autonomous Transaction Processing&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It's time to configure our DBeaver. The default JDBC Oracle Driver provided by the tool doesn't support Oracle Wallet. I had to download &lt;a href="https://www.oracle.com/database/technologies/appdev/jdbc-ucp-19-6-c-downloads.html"&gt;Oracle Database 19c (19.6) JDBC Driver&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I0IoJjhE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xn3efxhsvsex9c245jon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I0IoJjhE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xn3efxhsvsex9c245jon.png" alt="Alt Text" width="308" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;code&gt;Tools&lt;/code&gt; → &lt;code&gt;Driver Manager&lt;/code&gt; in DBeaver to create a copy of a Oracle driver configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ipHkgcI1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cvqapja9gnc5xxki9o32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ipHkgcI1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/cvqapja9gnc5xxki9o32.png" alt="Alt Text" width="436" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this new configuration, change the default files to the JAR files included in 19.6 JDBC .zip driver. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_ggFpzMh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/nwvq4n8pczruqt82623r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_ggFpzMh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/nwvq4n8pczruqt82623r.png" alt="Alt Text" width="706" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name it &lt;code&gt;Oracle 19.6&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mLzkTzDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/wlphujmcga5gs6smvene.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mLzkTzDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/wlphujmcga5gs6smvene.png" alt="Alt Text" width="501" height="778"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;Database Navigator&lt;/code&gt;, &lt;code&gt;Create&lt;/code&gt; a &lt;code&gt;New Connection&lt;/code&gt;. Select our new driver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q5zg6B9o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/x29x2tuogvljqi62u180.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q5zg6B9o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/x29x2tuogvljqi62u180.png" alt="Alt Text" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will provide a custom JDBC URL for our &lt;code&gt;Transaction Processing&lt;/code&gt; database connection. For the URL and other fields we need some simple informations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Service name&lt;/td&gt;
&lt;td&gt;dbtp20gb19cshr_tp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet location path&lt;/td&gt;
&lt;td&gt;/Users/.../Downloads/Wallet_DBTP20GB19cSHR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Username&lt;/td&gt;
&lt;td&gt;ADMIN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password&lt;/td&gt;
&lt;td&gt;DBTP20GB19cSHR (we set our database name 🤪 )&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is the shape of the URL for Oracle Wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdbc:oracle:thin:@dbtp20gb19cshr_tp?TNS_ADMIN=/Users/pinei/Downloads/Wallet_DBTP20GB19cSHR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After filling the fields, test the connection. For the first connection there can be a little lag.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V7mMnoQT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/0d094ej2oy79mr5qd49q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V7mMnoQT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/0d094ej2oy79mr5qd49q.png" alt="Alt Text" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can click &lt;code&gt;Finish&lt;/code&gt; to create the connection configuration.&lt;/p&gt;

&lt;p&gt;We can repeat the process for the Data Warehouse Database using these values:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Info&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Service name&lt;/td&gt;
&lt;td&gt;dbwh20gb19cshr_medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet location path&lt;/td&gt;
&lt;td&gt;/Users/.../Downloads/Wallet_DBTP20GB19cSHR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Username&lt;/td&gt;
&lt;td&gt;ADMIN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password&lt;/td&gt;
&lt;td&gt;DBWH20GB19cSHR (we set our database name 🤪 )&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdbc:oracle:thin:@dbwh20gb19cshr_medium?TNS_ADMIN=/Users/pinei/Downloads/Wallet_DBTP20GB19cSHR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can rename the connections afterward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0ApXqSOQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8evfj9fy5qx7yx2xf38t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0ApXqSOQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/8evfj9fy5qx7yx2xf38t.png" alt="Alt Text" width="434" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We didn't need the wallet password for our configuration, but the Java KeyStore (JKS) method makes use of it. If you want to try, see &lt;a href="https://docs.oracle.com/en/cloud/paas/autonomous-data-warehouse-cloud/user/connect-jdbc-thin-wallet.html#GUID-5ED3C08C-1A84-4E5A-B07A-A5114951AA9E"&gt;JDBC Thin Connections and Wallets&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article won't stop here, but with this content I decided to publish. More to come ...&lt;/p&gt;

</description>
      <category>database</category>
      <category>java</category>
    </item>
    <item>
      <title>First steps with Haskell</title>
      <dc:creator>Pinei</dc:creator>
      <pubDate>Wed, 19 Aug 2020 05:02:12 +0000</pubDate>
      <link>https://forem.com/pinei/first-steps-with-haskell-49l6</link>
      <guid>https://forem.com/pinei/first-steps-with-haskell-49l6</guid>
      <description>&lt;p&gt;This is my first article at &lt;strong&gt;Dev.to&lt;/strong&gt;. I'm not used to writing in English, but I am thinking of get some practice while learning pure functional programming with &lt;strong&gt;Haskell&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Haskell is a 90's programming language characterized by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi OS (Windows, Mac, Linux)&lt;/li&gt;
&lt;li&gt;General purpose (like C#, Java, C, C++)&lt;/li&gt;
&lt;li&gt;Purely functional (like Elm)&lt;/li&gt;
&lt;li&gt;Strong static typing (like Java, C, C++)&lt;/li&gt;
&lt;li&gt;Type inference (like OCaml, Haskell, Scala, Kotlin)&lt;/li&gt;
&lt;li&gt;Lazy evaluation&lt;/li&gt;
&lt;li&gt;Concise programs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Haskell has a diverse range of use commercially, from aerospace and defense, to finance, to web startups, hardware design firms and lawnmower manufacturers (&lt;a href="https://wiki.haskell.org/Haskell_in_industry"&gt;Haskell Wiki&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The language is widely known as a functional programming language which is great to write pure code and immutable data structures. It has a great support for a wide variety of concurrency models too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Functional programming&lt;/strong&gt; is a style of programming in which the basic method of computation is the application of functions to arguments, encouraging us to build software by composing functions in a declarative way (rather than imperative), avoiding shared state and mutable data.&lt;/p&gt;

&lt;p&gt;In a &lt;strong&gt;pure functional language&lt;/strong&gt;, you can't do anything that has a side effect. As a benefit, the language compiler can be a set of pure mathematical transformations. This results in much better high-level optimization facilities. &lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;side effect&lt;/strong&gt; would mean that evaluating an expression changes some internal state that would later cause evaluating the same expression to have a different result. In a pure functional language we can evaluate the same expression as often as we want with the same arguments, and it would always return the same value, because there is no state to change. (&lt;a href="https://stackoverflow.com/questions/4382223/what-does-pure-mean-in-pure-functional-language"&gt;What does “pure” mean in “pure functional language”?&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;In Haskell, even functions based on system inputs and outputs (like &lt;code&gt;print&lt;/code&gt;, &lt;code&gt;getChar&lt;/code&gt; and &lt;code&gt;getSystemTime&lt;/code&gt;) are pure. They handle &lt;code&gt;IO&lt;/code&gt; actions (where IO is a &lt;em&gt;monad&lt;/em&gt;, like Javascript &lt;code&gt;Promises&lt;/code&gt; is) which can be combined and performed by runtime. We can say that &lt;code&gt;getSystemTime&lt;/code&gt; is a constant which represents the action of getting the current time. This action is the same every time no matter when it is used. (&lt;a href="https://wiki.haskell.org/IO_inside"&gt;IO Inside&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;A language is &lt;strong&gt;statically typed&lt;/strong&gt; if the type of a variable is known at compile time. For some languages this means that you as the programmer must specify what type each variable is (e.g.: Java, C, C++); other languages offer some form of &lt;em&gt;type inference&lt;/em&gt;, the capability of the type system to deduce the type of a variable.&lt;/p&gt;

&lt;p&gt;The main advantage here is that all kinds of checking can be done by the compiler, and therefore a lot of trivial bugs and a very large class of program errors are caught at a very early stage. (&lt;a href="https://stackoverflow.com/questions/1517582/what-is-the-difference-between-statically-typed-and-dynamically-typed-languages/"&gt;What is the difference between statically typed and dynamically typed languages?&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lazy evaluation&lt;/strong&gt; means that expressions are not evaluated when they are bound to variables, but their evaluation is deferred until their results are needed. When it is evaluated, the result is saved so repeated evaluation is not needed.&lt;/p&gt;

&lt;p&gt;Lazy evaluation is a technique that can make some algorithms easier to express compactly and much more efficiently. It encourages programming in a modular style using intermediate data structures, and even allows data structures with an infinite number of elements. (&lt;a href="https://www.cs.nott.ac.uk/~pszgmh/pih.html"&gt;Programming in Haskell&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Imagine an infinite data structure like a &lt;strong&gt;Fibonacci list&lt;/strong&gt;. We don't actually figure out what the next element is until you actually ask for it. (&lt;a href="https://riptutorial.com/haskell/example/12240/fibonacci--using-lazy-evaluation"&gt;Fibonacci, Using Lazy Evaluation&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fibs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;zipWith&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;fibs&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="n"&gt;fibs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="n"&gt;fibs&lt;/span&gt;        &lt;span class="c1"&gt;-- [0,1,1,2,3,5,8,13,21,34]&lt;/span&gt;
&lt;span class="n"&gt;fibs&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;            &lt;span class="c1"&gt;-- 55&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have to understand some functions and operators to interpret the code above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;:&lt;/code&gt; operator prepends an element to a list&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tail&lt;/code&gt; function returns a list without its first element&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zipWith&lt;/code&gt; uses a specified function (in this case &lt;code&gt;addition&lt;/code&gt;) to combine corresponding elements of two lists (in this case &lt;code&gt;fibs&lt;/code&gt; and &lt;code&gt;tail fibs&lt;/code&gt;) to produce a third&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;take&lt;/code&gt; returns a sized prefix of a list&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!!&lt;/code&gt; is the list index (subscript) operator, starting from 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another nice example is a definition for an infinite list of integers (starting at 2) where each number is not divisible by any previous number in the list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filterPrime&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="kr"&gt;where&lt;/span&gt; &lt;span class="n"&gt;filterPrime&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;filterPrime&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="n"&gt;primes&lt;/span&gt;      &lt;span class="c1"&gt;-- [2,3,5,7,11,13,17,19,23,29]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Due to high-level nature of the functional style, programs written in Haskell are often much more &lt;strong&gt;concise&lt;/strong&gt; than in others languages. The language syntax was designed with concise programs in mind.&lt;/p&gt;

&lt;p&gt;These are the main concepts for now. To start testing and learning, let’s get our hands dirty.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Haskell platform
&lt;/h2&gt;

&lt;p&gt;A Haskell distribution may includes tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Glasgow Haskell Compiler&lt;/li&gt;
&lt;li&gt;the Cabal build system&lt;/li&gt;
&lt;li&gt;the Stack tool&lt;/li&gt;
&lt;li&gt;core &amp;amp; widely-used packages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Glasgow Haskell Compiler (GHC) is an open source compiler and interactive environment (aka GHCi) for the language Haskell.&lt;/p&gt;

&lt;p&gt;Let's see some concepts from the &lt;em&gt;Cabal build system&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CABAL&lt;/code&gt; (the spec) is the Common Architecture for Building Applications &amp;amp; Libraries. It’s a specification for defining how Haskell applications and libraries should be built, defining dependencies, etc.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.cabal&lt;/code&gt; (the file format) is used to write down the definitions for a specific package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;library
  exposed-modules:     HelloWorld
  -- other-modules:
  -- other-extensions:
  build-depends:       base &amp;gt;= 4.11 &amp;amp;&amp;amp; &amp;lt;4.12
  hs-source-dirs:      src
  default-language:    Haskell2010
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Cabal library&lt;/code&gt; implements the above specification and file format.&lt;/p&gt;

&lt;p&gt;The cabal executable (&lt;code&gt;cabal-install&lt;/code&gt;), is a command-line tool that uses Cabal (the library) to resolve dependencies and build packages.&lt;/p&gt;

&lt;p&gt;What about &lt;strong&gt;Stack&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Stack is a replacement for &lt;code&gt;cabal-install&lt;/code&gt;, i.e. the cabal executable. It is a build tool that works on top of the Cabal build system, with a focus on reproducible build plans and multi-package projects.&lt;/p&gt;

&lt;p&gt;We can also count on online package repositories to complement the build system:&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://hackage.haskell.org/"&gt;Hackage package repository&lt;/a&gt;, providing more than ten thousand open source libraries and applications to help you get your work done&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.stackage.org/"&gt;Stackage package collection&lt;/a&gt;, a curated set of packages from Hackage which are regularly tested for compatibility. Stack defaults to using Stackage package sets to avoid dependency problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with Stack
&lt;/h2&gt;

&lt;p&gt;In my computer I have the &lt;code&gt;brew&lt;/code&gt; tool installed (a package manager for macOS and Linux)&lt;/p&gt;

&lt;p&gt;With a simple command I was able to download and install the mentioned tools to start with Haskell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ brew install haskell-stack
...
🍺  /usr/local/Cellar/haskell-stack/2.3.3: 6 files, 55.4MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;stack&lt;/code&gt; command starts our Haskell Interpreter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ stack ghci
...
Configuring GHCi with the following packages:
GHCi, version 8.8.3: https://www.haskell.org/ghc/  :? for help
Prelude&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Prelude&lt;/code&gt; is a module that contains a small set of standard definitions and is included automatically into all Haskell modules.&lt;/p&gt;

&lt;p&gt;Let's do a simple test and quit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prelude&amp;gt; let x = 12 in x / 4
3.0
Prelude&amp;gt; :quit
Leaving GHCi.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The first project
&lt;/h2&gt;

&lt;p&gt;With Stack and a template we can generate a start project inside our current directory, but it suggest us to config some properties in advance. We can set these properties in the &lt;code&gt;~/.stack/config.yaml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;templates:
  params:
    author-name: Aldinei
    author-email: aldinei@gmail.com
    copyright: none
    github-username: pinei
    category: Development
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use &lt;code&gt;stack new&lt;/code&gt; to create our first Haskell project called &lt;code&gt;haskell-kitchen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can access &lt;a href="https://github.com/commercialhaskell/stack-templates"&gt;stack-templates&lt;/a&gt; to search for another template. Here the default "new-template" will be used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ stack new haskell-kitchen
Downloading template "new-template" to create project "haskell-kitchen" in haskell-kitchen/ ...
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- haskell-kitchen/
...
Initialising configuration using resolver: lts-16.10
Total number of user packages considered: 1
Writing configuration to file: haskell-kitchen/stack.yaml
All done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;stack new&lt;/code&gt; command should have created the following files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
│   └── Main.hs
├── ChangeLog.md
├── LICENSE
├── haskell-kitchen.cabal
├── package.yaml
├── README.md
├── Setup.hs
├── src
│   └── Lib.hs
├── stack.yaml
└── test
    └── Spec.hs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see some text files and source folders (&lt;code&gt;app&lt;/code&gt;, &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;) containing &lt;code&gt;.hs&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;package.yaml&lt;/code&gt; is the preferred package format provided by Stack. The default behaviour is to generate the &lt;code&gt;.cabal&lt;/code&gt; file from this &lt;code&gt;package.yaml&lt;/code&gt;, so you should not modify the &lt;code&gt;.cabal&lt;/code&gt; file. It is updated automatically as part of the stack build process.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Setup.hs&lt;/code&gt; file is another component of the Cabal build system. It's technically not needed by Stack, but it is still considered good practice in the Haskell world to include it.&lt;/p&gt;

&lt;p&gt;The project descriptor named &lt;code&gt;stack.yaml&lt;/code&gt; gives our project-level settings.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;src\Lib.hs&lt;/code&gt; source file, let's type a text in the function &lt;code&gt;someFunc&lt;/code&gt; of the &lt;code&gt;Lib&lt;/code&gt; module to see it printed to the output later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Lib&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;someFunc&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="n"&gt;someFunc&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;someFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;putStrLn&lt;/span&gt; &lt;span class="s"&gt;"Welcome to Haskell Kitchen"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see the &lt;code&gt;app\Main.hs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Main&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Lib&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;someFunc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function named &lt;code&gt;main&lt;/code&gt; in the module &lt;code&gt;Main&lt;/code&gt; is special. It is defined to be the entry point of a Haskell program (similar to the main function in C), and must have an &lt;code&gt;IO type&lt;/code&gt;, usually &lt;code&gt;IO ()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our module &lt;code&gt;Lib&lt;/code&gt; is imported here and the function &lt;code&gt;someFunc&lt;/code&gt; will be invoked.&lt;/p&gt;

&lt;p&gt;Now let's see the &lt;code&gt;test\Spec.hs&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main :: IO ()
main = putStrLn "Test suite not yet implemented"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It would be interesting to write some tests to learn and document some codes, but with this sample we haven't any clue about how to write the test cases. It's a subject for another article.&lt;/p&gt;

&lt;p&gt;Let's use Stack to run our &lt;code&gt;hello-world&lt;/code&gt; application. Type &lt;code&gt;stack build&lt;/code&gt; to generate the binary ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ stack build
haskell-kitchen&amp;gt; configure (lib + exe)
Configuring haskell-kitchen-0.1.0.0...
haskell-kitchen&amp;gt; build (lib + exe)
Preprocessing library for haskell-kitchen-0.1.0.0..
Building library for haskell-kitchen-0.1.0.0..
Preprocessing executable 'haskell-kitchen-exe' for haskell-kitchen-0.1.0.0..
Building executable 'haskell-kitchen-exe' for haskell-kitchen-0.1.0.0..
[1 of 2] Compiling Main [Lib changed]
Linking .../haskell-kitchen-exe ...
haskell-kitchen&amp;gt; copy/register
Registering library for haskell-kitchen-0.1.0.0..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The binaries for the local platform (in my case x86_64-osx) are generated somewhere in the folder &lt;code&gt;.stack-work&lt;/code&gt; under the project folder.&lt;/p&gt;

&lt;p&gt;The command &lt;code&gt;stack exec&lt;/code&gt; helps us to find the executable and run it ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ stack exec haskell-kitchen-exe
Welcome to Haskell Kitchen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is showing as expected. In a near future we can build a functional application.&lt;/p&gt;

&lt;p&gt;For now let's test some code writing a new module in &lt;code&gt;src\Calculator.hs&lt;/code&gt; for simple recursive functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Calculator&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;product&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="n"&gt;double&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Num&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;double&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;sum_list&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Num&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;sum_list&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;sum_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sum_list&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;

&lt;span class="n"&gt;product_list&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Num&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;product_list&lt;/span&gt;&lt;span class="kt"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;product_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;product_list&lt;/span&gt; &lt;span class="n"&gt;xs&lt;/span&gt;

&lt;span class="n"&gt;factorial&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Integral&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product_list&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can try the functions using the GHCi environment. Execute &lt;code&gt;stack ghci&lt;/code&gt; in the project folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ stack ghci
Using main module: 1. Package `haskell-kitchen' component haskell-kitchen:exe:haskell-kitchen-exe with main-is file: ./haskell-kitchen/app/Main.hs
haskell-kitchen&amp;gt; configure (lib + exe)
Configuring haskell-kitchen-0.1.0.0...
haskell-kitchen&amp;gt; initial-build-steps (lib + exe)
Configuring GHCi with the following packages: haskell-kitchen
GHCi, version 8.8.3: https://www.haskell.org/ghc/  :? for help
[1 of 3] Compiling Calculator       ( ./haskell-kitchen/src/Calculator.hs, interpreted )
[2 of 3] Compiling Lib              ( ./haskell-kitchen/src/Lib.hs, interpreted )
[3 of 3] Compiling Main             ( ./haskell-kitchen/app/Main.hs, interpreted )
Ok, three modules loaded.
*Main Calculator Lib&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have 3 modules compiled and loaded, and we are able to invoke the functions from the &lt;code&gt;Calculator&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Prelude&lt;/code&gt; module in the prompt gave way to a list of our loaded modules &lt;code&gt;Main Calculator Lib&lt;/code&gt;. We can configure the prompt using &lt;code&gt;:set prompt "&amp;gt; "&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*Main Calculator Lib&amp;gt; :set prompt "&amp;gt; "
&amp;gt; Calculator.double 3
6
&amp;gt; Calculator.sum [1..5]
15
&amp;gt; Calculator.product [2, 3]
6
&amp;gt; Calculator.factorial 5
120
&amp;gt; :quit
Leaving GHCi.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems our functions are working well, but we can make our project better with unit tests. I have to search for options before writing a second article in a series.&lt;/p&gt;

</description>
      <category>haskell</category>
    </item>
  </channel>
</rss>
