<?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: Daniel Reis</title>
    <description>The latest articles on Forem by Daniel Reis (@danielhe4rt).</description>
    <link>https://forem.com/danielhe4rt</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%2F468493%2Fa21c704e-4f35-49da-8c80-8bf0741c76dc.png</url>
      <title>Forem: Daniel Reis</title>
      <link>https://forem.com/danielhe4rt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/danielhe4rt"/>
    <language>en</language>
    <item>
      <title>Data Engineering 101 - A real beginner's approach</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Tue, 14 Oct 2025 00:30:14 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/data-engineering-101-a-real-beginners-approach-25a8</link>
      <guid>https://forem.com/danielhe4rt/data-engineering-101-a-real-beginners-approach-25a8</guid>
      <description>&lt;p&gt;This is the article about Data Engineering that you find if you search the subject on Google and get redirected after click &lt;strong&gt;Feeling Lucky&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Also, this article is a POV of an experienced webdev engineer that started a new topic in his career, that means: that's my study, my research, if you have anything to add, feel free to teach me in the comments below! I would love to learn more!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Prologue&lt;/li&gt;
&lt;li&gt;
2. First Impressions: Exploring Bruin’s Structure

&lt;ul&gt;
&lt;li&gt;
2.1. Core File: &lt;code&gt;.bruin.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
2.2. Pipeline: A Way Easier Apache Airflow
&lt;/li&gt;
&lt;li&gt;
2.3. Assets: The Building Blocks of Data Products
&lt;/li&gt;
&lt;li&gt;
2.4. Policies: Enforcing Quality and Governance
&lt;/li&gt;
&lt;li&gt;2.5. Glossary: Speaking the Same Language&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

3. Building Our First Pipeline

&lt;ul&gt;
&lt;li&gt;
3.1. Step 1: Ingest from Your Source to a Data Lake
&lt;/li&gt;
&lt;li&gt;
3.2. Step 2: Formatting and Validating the Data (Staging Layer)
&lt;/li&gt;
&lt;li&gt;
3.3. Step 3: Designing the Analytics (Mart) Layer
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;4. Full Preview Data Flow&lt;/li&gt;

&lt;li&gt;5. Overpowered VS Code Extension&lt;/li&gt;

&lt;li&gt;6. Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prologue
&lt;/h2&gt;

&lt;p&gt;I have to admit: whenever someone mentioned &lt;strong&gt;Data Engineering&lt;/strong&gt;, I used to tune out. It always sounded like something impossibly complex — almost &lt;em&gt;magical&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This week, I finally decided to dive in. I thought it would be fairly straightforward, but it didn’t take long to realize how deep the rabbit hole goes.&lt;/p&gt;

&lt;p&gt;This field isn’t just a few scripts or SQL queries; it’s an entire &lt;strong&gt;ecosystem&lt;/strong&gt; of interconnected tools, concepts, and responsibilities that form the backbone of modern data systems.&lt;/p&gt;

&lt;p&gt;Concepts like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Catalogs and Governance:&lt;/strong&gt; understanding who owns the data, how to ensure quality, and how to track lineage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; coordinating dependencies and workflows with tools like &lt;strong&gt;Apache Airflow&lt;/strong&gt; or &lt;strong&gt;Dagster&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transformation (ETL/ELT):&lt;/strong&gt; cleaning and standardizing data using tools such as &lt;strong&gt;dbt&lt;/strong&gt; or &lt;strong&gt;Fivetran&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingestion and Streaming:&lt;/strong&gt; connecting sources and moving data in real time with &lt;strong&gt;Kafka&lt;/strong&gt;, &lt;strong&gt;Airbyte&lt;/strong&gt;, or &lt;strong&gt;Confluent Cloud&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability and Quality:&lt;/strong&gt; monitoring data health with solutions like &lt;strong&gt;Monte Carlo&lt;/strong&gt; and &lt;strong&gt;Datafold&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each article clicked, just opened up a new world of tools, words, frameworks, architectures, and best practices.&lt;br&gt;
And somehow, all of it &lt;strong&gt;has to work together&lt;/strong&gt; — governance, orchestration, transformation, ingestion, observability, infrastructure.&lt;/p&gt;

&lt;p&gt;As a developer, I’m used to learning a &lt;strong&gt;language&lt;/strong&gt; and a &lt;strong&gt;framework&lt;/strong&gt; and then getting to work.&lt;br&gt;
But in data engineering, it’s different.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It’s about understanding an entire &lt;strong&gt;ecosystem&lt;/strong&gt; and how each piece connects to the next.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After hours of reading docs, chasing GitHub repos, and jumping between tools, articles, and endless definitions, I finally found &lt;strong&gt;the tool&lt;/strong&gt; that made everything click — &lt;strong&gt;Bruin&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Imagine a single framework that:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pipelines as Code&lt;/strong&gt; — Everything lives in version-controlled text (YAML, SQL, Python). No hidden UIs or databases. Reproducible, reviewable, and automatable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Language by Nature&lt;/strong&gt; — Native support for SQL and Python, plus the ability to plug in binaries or containers for more complex use cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composable Pipelines&lt;/strong&gt; — Combine technologies, sources, and destinations in one seamless flow — no glue code, no hacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Lock-In&lt;/strong&gt; — 100% open-source (Apache-licensed) CLI that runs anywhere: locally, in CI, or in production. You keep full control of your pipelines and data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built for Developers and Data Quality&lt;/strong&gt; — Fast local runs, integrated checks, and quick feedback loops. Data products that are tested, trusted, and easy to ship.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…and it &lt;strong&gt;fits all the core Data Engineering concepts&lt;/strong&gt; I just mentioned earlier.&lt;/p&gt;

&lt;p&gt;I’ll admit it — I’m the kind of person who embraces &lt;em&gt;productive laziness&lt;/em&gt;. If there’s a way to do more with fewer tools and less friction, I’m in.&lt;/p&gt;

&lt;p&gt;So before we get started, here’s the plan:&lt;/p&gt;

&lt;p&gt;In most setups, data flows from OLTP databases → ingestion → data lake/warehouse → transformation → marts → analytics dashboards.  &lt;/p&gt;

&lt;p&gt;Tools like &lt;strong&gt;Airbyte&lt;/strong&gt; handle ingestion, &lt;strong&gt;dbt&lt;/strong&gt; handles transformation, &lt;strong&gt;Airflow&lt;/strong&gt; orchestrates dependencies — and Bruin combines those layers &lt;br&gt;
into one unified framework.&lt;/p&gt;

&lt;p&gt;This article will walk through the &lt;strong&gt;fundamental principles of Data Engineering&lt;/strong&gt;, while exploring how &lt;strong&gt;Bruin&lt;/strong&gt; brings them all together through a simple, real-world pipeline.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. First Impressions: Exploring Bruin’s Structure
&lt;/h2&gt;

&lt;p&gt;I’ll be honest — I used to have a bit of a bias against Data Science/Engineering projects. Every time I looked at one, it felt messy and unstructured, with files and notebooks scattered everywhere. Coming from a software development background, that kind of chaos always bothered me.&lt;/p&gt;

&lt;p&gt;But once I started looking at &lt;strong&gt;Bruin’s project structure&lt;/strong&gt;, that perception completely changed. Everything suddenly felt &lt;strong&gt;organized and intentional&lt;/strong&gt;.&lt;br&gt;
The framework naturally enforces structure through its layers — and once you follow them, everything starts to make sense.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example: Project Structure
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── duckdb.db  
├── ecommerce-mart  
│ ├── assets  
│ │ ├── ingestion  
│ │ │ ├── raw.customers.asset.yml  
│ │ │ ├── raw.order_items.asset.yml  
│ │ │ ├── raw.orders.asset.yml  
│ │ │ ├── raw.products.asset.yml  
│ │ │ └── raw.product_variants.asset.yml  
│ │ ├── mart  
│ │ │ ├── mart.customers-by-age.asset.py  
│ │ │ ├── mart.customers-by-country.asset.yml  
│ │ │ ├── mart.product_performance.sql  
│ │ │ ├── mart.sales_daily.sql  
│ │ │ └── mart.variant_profitability.sql  
│ │ └── staging  
│ │ ├── stg.customers.asset.yml  
│ │ ├── stg.order_items.sql  
│ │ ├── stg.orders.sql  
│ │ ├── stg.products.sql  
│ │ └── stg.product_variants.sql  
│ └── pipeline.yml  
├── glossary.yml  
├── policy.yml  
└── .bruin.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What Each Part Does
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.bruin.yml&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The main configuration file for your Bruin environment.&lt;/li&gt;
&lt;li&gt;Defines &lt;strong&gt;global settings&lt;/strong&gt; like default &lt;strong&gt;connections&lt;/strong&gt;, variables, and &lt;strong&gt;behavior&lt;/strong&gt; for all pipelines.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;policy.yml&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Your data governance and validation policy file.&lt;/li&gt;
&lt;li&gt;Defines data quality rules, access controls, and compliance checks that Bruin can automatically enforce before shipping data products.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;glossary.yml&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Works as a lightweight data catalog for your project.&lt;/li&gt;
&lt;li&gt;Documents terms, metrics, and datasets so everyone on the team speaks the same language.&lt;/li&gt;
&lt;li&gt;Also helps with lineage, documentation, and discoverability.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;some-feature/pipeline.yml&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Defines a specific pipeline for a domain or project (in this example, &lt;em&gt;ecommerce&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Describes the end-to-end data flow — which assets to run, their dependencies, and schedules.&lt;/li&gt;
&lt;li&gt;Pipelines are modular, so you can maintain separate ones for different business domains.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;some-feature/assets/*&lt;/code&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Contains all the assets — the building blocks of your data pipelines.&lt;/li&gt;
&lt;li&gt;Each asset handles a distinct task: ingesting raw data, transforming it, or generating analytical tables.&lt;/li&gt;
&lt;li&gt;Since every asset is a file, it’s &lt;strong&gt;version-controlled, testable, and reusable&lt;/strong&gt; — just like code.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With just that, we're able to run a full pipeline. However, I still think we need to go through each step and file individually — I promise it’ll be quick!&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1. Core File: &lt;code&gt;.bruin.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Think of &lt;code&gt;.bruin.yml&lt;/code&gt; as the &lt;strong&gt;root configuration&lt;/strong&gt; of your project — the file that tells Bruin &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;where&lt;/em&gt; to run everything.&lt;/p&gt;

&lt;p&gt;Instead of scattering settings across scripts or environment variables, Bruin centralizes them here: connections, credentials, and environment-specific configurations all live in one place.&lt;br&gt;
It also serves as Bruin’s &lt;strong&gt;default secrets backend&lt;/strong&gt;, so your pipelines can access databases or warehouses securely and consistently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin run ecommerce/pipeline.yml &lt;span class="nt"&gt;--config-file&lt;/span&gt; /path/to/.bruin.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A simple example:&lt;/strong&gt;&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="na"&gt;default_environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;

&lt;span class="na"&gt;environments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&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;pg-default&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt; &lt;span class="c1"&gt;# (hardcoded as well)&lt;/span&gt;
          &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${PG_PASSWORD}&lt;/span&gt;
          &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${PG_HOST}&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${PG_PORT}&lt;/span&gt;
          &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${PG_DATABASE}&lt;/span&gt;

      &lt;span class="na"&gt;duckdb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&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;duckdb-default&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;duckdb.db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What’s Happening Here
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;default_environment&lt;/code&gt;&lt;/strong&gt; — sets the environment Bruin will use unless specified otherwise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;environments&lt;/code&gt;&lt;/strong&gt; — defines multiple setups (e.g., &lt;em&gt;dev&lt;/em&gt;, &lt;em&gt;staging&lt;/em&gt;, &lt;em&gt;prod&lt;/em&gt;), each with its own configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;connections&lt;/code&gt;&lt;/strong&gt; — lists every system Bruin can connect to, like Postgres or DuckDB.
Each connection gets a name (e.g., &lt;code&gt;pg-default&lt;/code&gt;) that you’ll reference across pipelines and assets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment variable support&lt;/strong&gt; — any value wrapped in &lt;code&gt;${...}&lt;/code&gt; will be automatically read from your system environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means you can keep credentials out of source control while still running locally or in CI/CD environments.&lt;/p&gt;

&lt;p&gt;This design keeps everything &lt;strong&gt;centralized, secure, and version-controlled&lt;/strong&gt;, while giving you the flexibility to inject secrets dynamically through environment variables — perfect for switching between local, staging, and production without touching the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2. Pipeline: A WAY EASIER Apache Airflow
&lt;/h3&gt;

&lt;p&gt;For each feature you have, it will have to come with a &lt;code&gt;pipeline.yml&lt;/code&gt; file.&lt;br&gt;
This is the file that will group all your assets and understand that it's not a single asset running, but a chained list of assets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- ecommerce-mart/
  ├─ pipeline.yml -&amp;gt; you're here
  └─ assets/
    ├─ some-asset.sql
    ├─ definitely-an-asset.yml
    └─ another-asset.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you also configure each connection you want to use on the specific pipeline:&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product_ecommerce_marts&lt;/span&gt;
&lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;daily&lt;/span&gt; &lt;span class="c1"&gt;# relevant for Bruin Cloud deployments&lt;/span&gt;

&lt;span class="na"&gt;default_connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;duckdb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duckdb-default"&lt;/span&gt;
  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg-default"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3. Assets: The Building Blocks of Data Products
&lt;/h3&gt;

&lt;p&gt;Every data pipeline in &lt;strong&gt;Bruin&lt;/strong&gt; is composed of &lt;strong&gt;assets&lt;/strong&gt; — modular, self-contained units that define a specific operation: ingesting, transforming, or producing a dataset.&lt;/p&gt;

&lt;p&gt;Each asset exists as a file under the &lt;code&gt;assets/&lt;/code&gt; directory, and its filename doubles as its identity inside the pipeline graph.&lt;/p&gt;

&lt;p&gt;If you remember the file structure shown in the beginning, you must remember that I have multiple types of assets in the pipeline. That's the most cool part, since you can write down in multiple languages and still being something simple. Here's some possibilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Filename (in the file tree)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;Declarative configuration for ingestion or metadata-heavy assets&lt;/td&gt;
&lt;td&gt;&lt;code&gt;raw.customers.asset.yml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL&lt;/td&gt;
&lt;td&gt;Pure transformation logic — think dbt-style models&lt;/td&gt;
&lt;td&gt;&lt;code&gt;stg.orders.sql&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Custom logic or integrations (e.g., APIs, validations, or machine learning steps)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mart.sales_daily.asset.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You’re free to organize assets however you like — there’s no rigid hierarchy to follow.&lt;br&gt;
The key insight is that &lt;strong&gt;the orchestration happens implicitly through dependencies&lt;/strong&gt;, not through an external DAG engine like Airflow.&lt;/p&gt;

&lt;p&gt;Each asset declares what it depends on, and &lt;strong&gt;Bruin automatically builds and executes the dependency graph&lt;/strong&gt; for you.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;raw.orders.asset.yml
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# raw.orders.asset.yml&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;raw.orders&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingestr&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;Ingest OLTP orders from Postgres into the DuckDB raw layer.&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;source_connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pg-default&lt;/span&gt;
  &lt;span class="na"&gt;source_table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public.orders"&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;duckdb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;raw.order_items.asset.yml
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# raw.order_items.asset.yml&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;raw.order_items&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingestr&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;Ingest OLTP order_items from Postgres into the DuckDB raw layer.&lt;/span&gt;
&lt;span class="na"&gt;depends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;raw.orders&lt;/span&gt;  &lt;span class="c1"&gt;# declares a dependency on the 'raw.orders' asset&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;source_connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pg-default&lt;/span&gt;
  &lt;span class="na"&gt;source_table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public.order_items"&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;duckdb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;... turns into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD
    raw.orders --&amp;gt; raw.order_items;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By chaining assets like this, you describe &lt;strong&gt;logical relationships&lt;/strong&gt; between data operations rather than manually orchestrating steps.&lt;br&gt;
The result is a &lt;strong&gt;declarative, composable, and maintainable pipeline&lt;/strong&gt; — easy to read, version, and extend just like application code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of the most powerful aspects of Bruin is how it connects &lt;strong&gt;data quality&lt;/strong&gt; and &lt;strong&gt;governance&lt;/strong&gt; directly into your assets.&lt;br&gt;
By defining checks under each column, you’re not only validating your data but also documenting ownership, expectations, and constraints — all version-controlled and enforceable at runtime.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means Bruin doesn’t just &lt;em&gt;run&lt;/em&gt; pipelines — it &lt;strong&gt;audits&lt;/strong&gt;, &lt;strong&gt;documents&lt;/strong&gt;, and &lt;strong&gt;governs&lt;/strong&gt; them as part of the same workflow.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.4. Policies: Enforcing Quality and Governance
&lt;/h3&gt;

&lt;p&gt;Policies in &lt;strong&gt;Bruin&lt;/strong&gt; act as the rulebook that keeps your data pipelines consistent, compliant, and high quality.&lt;br&gt;
They ensure every asset and pipeline follows best practices — from naming conventions and ownership to validation and metadata completeness.&lt;/p&gt;

&lt;p&gt;At their core, policies are defined in a single &lt;code&gt;policy.yml&lt;/code&gt; file located at the root of your project.&lt;br&gt;
This file lets you &lt;strong&gt;lint&lt;/strong&gt;, &lt;strong&gt;validate&lt;/strong&gt;, and &lt;strong&gt;enforce standards&lt;/strong&gt; automatically before a pipeline runs.&lt;/p&gt;
&lt;h4&gt;
  
  
  Quick Overview
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rulesets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&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;standard&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.*/ecommerce/.*&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;asset-has-owner&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;asset-name-is-lowercase&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;asset-has-description&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each &lt;strong&gt;ruleset&lt;/strong&gt; defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;where&lt;/strong&gt; the rule applies (&lt;code&gt;selector&lt;/code&gt; → match by path, tag, or name),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;what&lt;/strong&gt; to enforce (&lt;code&gt;rules&lt;/code&gt; → built-in or custom validation rules).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once defined, you can validate your entire project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin validate ecommerce

&lt;span class="c"&gt;# Validating pipelines in 'ecommerce' for 'default' environment...&lt;/span&gt;
&lt;span class="c"&gt;# Pipeline: ecommerce_pg_to_duckdb (.)&lt;/span&gt;
&lt;span class="c"&gt;#   raw.order_items (assets/ingestion/raw.order_items.asset.yml)&lt;/span&gt;
&lt;span class="c"&gt;#     └── Asset must have an owner (policy:standard:asset-has-owner)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bruin automatically lints assets before execution — ensuring that &lt;strong&gt;non-compliant pipelines never run&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Built-in and Custom Rules
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;asset-has-owner&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;asset&lt;/td&gt;
&lt;td&gt;Each asset must define an owner.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;asset-has-description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;asset&lt;/td&gt;
&lt;td&gt;Assets must include a description.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;asset-name-is-lowercase&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;asset&lt;/td&gt;
&lt;td&gt;Asset names must be lowercase.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pipeline-has-retries&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;pipeline&lt;/td&gt;
&lt;td&gt;Pipelines must define retry settings.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can also define your own rules:&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="na"&gt;custom_rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&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;asset-has-owner&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;every asset should have an owner&lt;/span&gt;
    &lt;span class="na"&gt;criteria&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;asset.Owner != ""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Rules can target either &lt;strong&gt;assets&lt;/strong&gt; or &lt;strong&gt;pipelines&lt;/strong&gt;, and they use logical expressions to determine compliance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Policies transform Bruin into a &lt;strong&gt;self-governing data platform&lt;/strong&gt; — one where best practices aren’t optional, they’re enforced.&lt;br&gt;
By committing your rules to version control, you make data governance part of the development workflow, not an afterthought.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.5. Glossary: Speaking the Same Language
&lt;/h3&gt;

&lt;p&gt;In data projects, one of the hardest problems isn’t technical — it’s &lt;strong&gt;communication&lt;/strong&gt;.&lt;br&gt;
Different teams often use the same word to mean different things.&lt;br&gt;
That’s where &lt;strong&gt;Bruin’s Glossary&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;A glossary is defined in &lt;code&gt;glossary.yml&lt;/code&gt; at the root of your project.&lt;br&gt;
It acts as a &lt;strong&gt;shared dictionary&lt;/strong&gt; of business concepts (like &lt;em&gt;Customer&lt;/em&gt; or &lt;em&gt;Order&lt;/em&gt;) and their attributes, keeping teams aligned across pipelines.&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="na"&gt;entities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Customer&lt;/span&gt;&lt;span class="pi"&gt;:&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;A registered user or business in our platform.&lt;/span&gt;
    &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&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;Unique customer identifier.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can reference these definitions inside assets using &lt;code&gt;extends&lt;/code&gt;, avoiding duplication and ensuring consistency:&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="c1"&gt;# raw.customers.asset.yml&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;raw.customers&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingestr&lt;/span&gt;

&lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&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;customer_id&lt;/span&gt;
    &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Customer.ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatically inherits the &lt;code&gt;type&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; from the glossary.&lt;br&gt;
It’s a simple idea, but a powerful one — your &lt;strong&gt;data definitions become version-controlled and shared&lt;/strong&gt;, just like code.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Building Our First Pipeline
&lt;/h2&gt;

&lt;p&gt;Now that we’ve explored the structure and philosophy behind &lt;strong&gt;Bruin&lt;/strong&gt;, it’s time to build an end-to-end pipeline.&lt;br&gt;&lt;br&gt;
We’ll go from &lt;strong&gt;raw ingestion&lt;/strong&gt; to a &lt;strong&gt;clean staging layer&lt;/strong&gt;, and finally, to &lt;strong&gt;analytics-ready marts&lt;/strong&gt; — all defined as code.&lt;/p&gt;

&lt;p&gt;We’ll assume you already have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Postgres&lt;/strong&gt; database as your data source.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;DuckDB&lt;/strong&gt; database as your analytical storage.&lt;/li&gt;
&lt;li&gt;A working &lt;code&gt;.bruin.yml&lt;/code&gt; file configured with both connections
### 3.1 Step 1 : Ingest from Your Source to a Data Lake&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step is to move data from Postgres into DuckDB.&lt;br&gt;&lt;br&gt;
This creates your &lt;strong&gt;Raw Layer&lt;/strong&gt; — data replicated from the source with minimal transformation.&lt;/p&gt;

&lt;p&gt;Create an ingestion asset file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;assets/ingestion/raw.customers.asset.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then define the asset:&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="c1"&gt;# assets/ingestion/raw.customers.asset.yml&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;raw.customers&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ingestr&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;Ingest OLTP customers from Postgres into the DuckDB raw layer.&lt;/span&gt;

&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;source_connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pg-default&lt;/span&gt;
  &lt;span class="na"&gt;source_table&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public.customers"&lt;/span&gt;
  &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;duckdb&lt;/span&gt;

&lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&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;id&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
    &lt;span class="na"&gt;primary_key&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;checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&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;not_null&lt;/span&gt;
      &lt;span class="pi"&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;unique&lt;/span&gt;

  &lt;span class="pi"&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;email&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&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;not_null&lt;/span&gt;
      &lt;span class="pi"&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;unique&lt;/span&gt;

  &lt;span class="pi"&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;country&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&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;not_null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Bruin to extract data from your Postgres table &lt;code&gt;public.customers&lt;/code&gt;, validate column quality, and store it in the DuckDB raw layer.&lt;/p&gt;




&lt;h4&gt;
  
  
  Running the Asset
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin run ecommerce/assets/ingestion/raw.customers.asset.yml 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyzed the pipeline 'ecommerce_pg_to_duckdb' with 13 assets.
Running only the asset 'raw.customers'

  Pipeline: ecommerce_pg_to_duckdb (../../..)
  No issues found                                                                                                                                                                                                                                  
✓ Successfully validated 13 assets across 1 pipeline, all good.                                                                                                 
  Interval: 2025-10-12T00:00:00Z - 2025-10-12T23:59:59Z

Starting the pipeline execution...
  PASS raw.customers ........

  bruin run completed successfully in 2.095s

✓ Assets executed      1 succeeded

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now query the ingested data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin query &lt;span class="nt"&gt;--connection&lt;/span&gt; duckdb-default &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM raw.customers LIMIT 5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────┬───────────────────┬───────────────────────────┬───────────┬──────────────────┬──────────────────────────────────────┬──────────────────────────────────────┐
│ ID │ FULL_NAME         │ EMAIL                     │ COUNTRY   │ CITY             │ CREATED_AT                           │ UPDATED_AT                           │
├────┼───────────────────┼───────────────────────────┼───────────┼──────────────────┼──────────────────────────────────────┼──────────────────────────────────────┤
│ 1  │ Allison Hill      │ donaldgarcia@example.net  │ Uganda    │ New Roberttown   │ 2025-10-10 18:19:13.083281 +0000 UTC │ 2025-10-10 00:42:59.71112 +0000 UTC  │
│ 2  │ David Guzman      │ jennifermiles@example.com │ Cyprus    │ Lawrencetown     │ 2025-10-10 07:52:47.643619 +0000 UTC │ 2025-10-10 06:23:42.864287 +0000 UTC │
│ 3  │ Caitlin Henderson │ eric51@example.org        │ Hong Kong │ West Melanieview │ 2025-10-10 21:06:02.639412 +0000 UTC │ 2025-10-10 19:23:17.540169 +0000 UTC │
│ 4  │ Monica Herrera    │ smiller@example.net       │ Niger     │ Barbaraland      │ 2025-10-11 01:33:43.032929 +0000 UTC │ 2025-10-10 02:29:27.22515 +0000 UTC  │
│ 5  │ Darren Roberts    │ wyattmichelle@example.com │ Fiji      │ Reidstad         │ 2025-10-10 12:05:18.734246 +0000 UTC │ 2025-10-10 00:51:13.406526 +0000 UTC │
└────┴───────────────────┴───────────────────────────┴───────────┴──────────────────┴──────────────────────────────────────┴──────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your &lt;strong&gt;raw layer&lt;/strong&gt; is now established and validated.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.2 Step 2: Formatting and Validating the Data (Staging Layer)
&lt;/h3&gt;

&lt;p&gt;Next, we’ll clean and standardize the ingested data before using it in analytics.&lt;br&gt;&lt;br&gt;
This layer is called &lt;strong&gt;Staging (stg)&lt;/strong&gt; — it’s where you enforce schema, column consistency, and apply business rules.&lt;/p&gt;

&lt;p&gt;Create the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;ecommerce/assets/staging/stg.customers.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And define it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* @bruin
name: stg.customers
type: duckdb.sql
materialization:
  type: table

depends:
  - raw.customers

checks:
  columns:
    id:
      - not_null
    email:
      - not_null
      - unique
    country:
      - not_null
@bruin */&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;TRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;TRIM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'Unknown'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;updated_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what’s happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Bruin annotation block (&lt;code&gt;@bruin&lt;/code&gt;)&lt;/strong&gt; defines metadata for the asset.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;depends&lt;/code&gt; key ensures this staging step &lt;strong&gt;only runs after&lt;/strong&gt; &lt;code&gt;raw.customers&lt;/code&gt; completes — Bruin automatically manages the dependency chain.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;column checks&lt;/strong&gt; ensure data quality before and after the transformation.&lt;/li&gt;
&lt;li&gt;The SQL query itself performs light cleaning and enforces type consistency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design mimics orchestration tools like &lt;strong&gt;Airflow&lt;/strong&gt;, but without external schedulers — dependencies and checks are declared right inside your code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Validation and Execution
&lt;/h4&gt;

&lt;p&gt;Before running, validate the asset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin validate ecommerce/assets/staging/stg.customers.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Pipeline: ecommerce_pg_to_duckdb &lt;span class="o"&gt;(&lt;/span&gt;.&lt;span class="o"&gt;)&lt;/span&gt;
  No issues found      

✓ Successfully validated 13 assets across 1 pipeline, all good.     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now execute it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin run ecommerce/assets/staging/stg.customers.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bruin run ecommerce/assets/staging/stg.customers.asset.sql
Analyzed the pipeline 'ecommerce_pg_to_duckdb' with 15 assets.
Running only the asset 'stg.customers'

Pipeline: ecommerce_pg_to_duckdb (../../..)
  No issues found                                                                                                                                                                                                                                   

✓ Successfully validated 15 assets across 1 pipeline, all good.                                                       

Interval: 2025-10-12T00:00:00Z - 2025-10-12T23:59:59Z

Starting the pipeline execution...

[21:28:16] Running:  stg.customers
[21:28:16] Finished: stg.customers (41ms)

==================================================

PASS stg.customers 


bruin run completed successfully in 41ms

 ✓ Assets executed      1 succeeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm that the transformation worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin query &lt;span class="s2"&gt;"SELECT country, COUNT(*) AS customers FROM stg.customers GROUP BY country ORDER BY customers DESC;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sample output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;country      | customers
--------------+-----------
BRAZIL        | 420
GERMANY       | 255
UNITED STATES | 198
ARGENTINA     | 190
SOUTH KOREA   | 182
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, you have a &lt;strong&gt;clean, validated dataset&lt;/strong&gt; ready for analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Step 3: Designing the Analytics (Mart) Layer
&lt;/h3&gt;

&lt;p&gt;The final step is to build your &lt;strong&gt;Mart Layer&lt;/strong&gt;, where business-ready data lives.&lt;br&gt;&lt;br&gt;
This is the layer analysts and dashboards query directly.&lt;br&gt;&lt;br&gt;
Each Mart asset aggregates or reshapes the staging data into meaningful datasets for reporting and analysis.&lt;/p&gt;
&lt;h4&gt;
  
  
  3.3.1 Asset: &lt;code&gt;mart.customers_by_country.asset.sql&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Create the following file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;ecommerce/assets/mart/mart.customers_by_country.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then define the asset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* @bruin
name: mart.customers_by_country
type: duckdb.sql

materialization:
  type: table

depends:
  - stg.customers
@bruin */&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;COUNT&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="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_customers&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;stg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;total_customers&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This SQL asset aggregates customers by country and depends on &lt;code&gt;stg.customers&lt;/code&gt;, ensuring the staging layer runs first.&lt;br&gt;&lt;br&gt;
It materializes as a table inside DuckDB.&lt;/p&gt;

&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin run ecommerce/assets/mart/mart.customers_by_country.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pipeline: ecommerce_pg_to_duckdb (.)
Running mart.customers_by_country
✓ Table materialized successfully in DuckDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin query &lt;span class="nt"&gt;--connection&lt;/span&gt; duckdb-default &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM mart.customers_by_country LIMIT 5;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────┬───────────────────┐
│ COUNTRY       │ TOTAL_CUSTOMERS   │
├───────────────┼───────────────────┤
│ BRAZIL        │ 420               │
│ GERMANY       │ 255               │
│ UNITED STATES │ 198               │
│ ARGENTINA     │ 190               │
│ SOUTH KOREA   │ 182               │
└───────────────┴───────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  3.3.2 Asset: &lt;code&gt;mart.customers_by_age.asset.sql&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Now, let’s create a second mart that segments customers into age groups.&lt;/p&gt;

&lt;p&gt;Create the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;ecommerce/assets/mart/mart.customers_by_age.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* @bruin
name: mart.customers_by_age  
type: duckdb.sql  

materialization:  
  type: table  
depends:  
  - stg.customers  

@bruin */&lt;/span&gt;  

&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="k"&gt;CASE&lt;/span&gt;  
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'18-24'&lt;/span&gt;  
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'25-34'&lt;/span&gt;  
      &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="k"&gt;BETWEEN&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="mi"&gt;49&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'35-49'&lt;/span&gt;  
      &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'50+'&lt;/span&gt;  
    &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;age_group&lt;/span&gt;  
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;stg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
  &lt;span class="n"&gt;age_group&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="k"&gt;COUNT&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="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_customers&lt;/span&gt;  
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;  
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;age_group&lt;/span&gt;  
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;total_customers&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This asset computes customer distribution by age brackets using a simple &lt;code&gt;CASE&lt;/code&gt; expression and aggregates the results.&lt;/p&gt;

&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin run ecommerce/assets/mart/mart.customers_by_age.asset.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bruin run ecommerce/assets/mart/mart.customers_by_age.asset.sql
Analyzed the pipeline 'ecommerce_pg_to_duckdb' with 15 assets.
Running only the asset 'mart.customers_by_age'

Pipeline: ecommerce_pg_to_duckdb (../../..)
  No issues found

✓ Successfully validated 15 assets across 1 pipeline, all good.

Interval: 2025-10-12T00:00:00Z - 2025-10-12T23:59:59Z

Starting the pipeline execution...

[21:10:24] Running:  mart.customers_by_age
[21:10:24] Finished: mart.customers_by_age (39ms)

==================================================

PASS mart.customers_by_age 


bruin run completed successfully in 39ms

 ✓ Assets executed      1 succeeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm that the mart is populated correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bruin query &lt;span class="nt"&gt;--connection&lt;/span&gt; duckdb-default &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM mart.customers_by_age;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────┬───────────────────┐
│ AGE_GROUP   │ TOTAL_CUSTOMERS   │
├─────────────┼───────────────────┤
│ 25-34       │ 460               │
│ 35-49       │ 310               │
│ 18-24       │ 250               │
│ 50+         │ 225               │
└─────────────┴───────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Full Preview Data Flow
&lt;/h3&gt;

&lt;p&gt;Hopefully, if I got it right, the concepts explained in the beginning didn't got that messy and we actually made the pipeline become a real thing only using Bruin and a couple of queries! &lt;/p&gt;

&lt;p&gt;Our example pipeline look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD
    raw.customers --&amp;gt; stg.customers
    stg.customers --&amp;gt; mart.customers_by_country
    stg.customers --&amp;gt; mart.customers_by_age
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, you’ve built a &lt;strong&gt;fully declarative, end-to-end data pipeline&lt;/strong&gt; with Bruin — ingestion, staging, and analytics —  all governed, validated, and reproducible, without any external orchestration layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Overpowered VS Code Extension
&lt;/h2&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%2Fn1kfdwcwqk72snh2rcqp.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%2Fn1kfdwcwqk72snh2rcqp.png" alt="VS Code Extension" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I first installed the &lt;strong&gt;Bruin VS Code Extension&lt;/strong&gt;, I had no idea what I was doing.&lt;br&gt;&lt;br&gt;
At that time, I didn’t really understand how &lt;strong&gt;Bruin&lt;/strong&gt; — or even &lt;strong&gt;Data Engineering&lt;/strong&gt; — worked.&lt;br&gt;&lt;br&gt;
I clicked around, saw a bunch of YAMLs and metadata markers, and quickly gave up.&lt;/p&gt;

&lt;p&gt;Week later, after finally understanding the ecosystem — ingestion, staging, marts, and governance — I decided to open the extension again, ad that’s when it &lt;strong&gt;all clicked&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It wasn’t just a helper. It was &lt;strong&gt;the missing piece&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The extension brings the same declarative power of Bruin’s CLI into a &lt;strong&gt;visual, developer-friendly environment&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
It automatically scans your assets, validates configurations, runs queries directly against your databases, and even manages your YAMLs in real time.  &lt;/p&gt;

&lt;p&gt;Everything happens inside VS Code — validation, lineage exploration, metadata checks, and query previews.&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%2Fvih8zkdijp1vkqf6n0l9.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%2Fvih8zkdijp1vkqf6n0l9.png" alt="VS Code Extension Details" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What impressed me most was how &lt;strong&gt;fluid and open&lt;/strong&gt; it is.  There’s &lt;strong&gt;no vendor lock-in&lt;/strong&gt; here — it’s completely open source.&lt;br&gt;&lt;br&gt;
You can fork it, extend it, or contribute back to the community just like the CLI itself.&lt;/p&gt;

&lt;p&gt;In short, the Bruin VS Code Extension isn’t just a companion — it’s the natural evolution of the workflow.  Once you understand Bruin, this tool feels like magic finally explained.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusion
&lt;/h2&gt;

&lt;p&gt;This study was my first real attempt to understand &lt;strong&gt;Bruin&lt;/strong&gt; and what &lt;strong&gt;Data Engineering&lt;/strong&gt; actually means in practice. What once felt abstract and complicated started to make a bit more sense after breaking things apart, experimenting, and connecting the dots one step at a time.&lt;/p&gt;

&lt;p&gt;I wouldn’t say I fully understand everything yet—far from it—but I can finally see how the pieces fit together: ingestion, staging, marts, validation, and governance. Bruin helped me get hands-on with those concepts in a way that felt approachable instead of overwhelming.&lt;/p&gt;

&lt;p&gt;The process of exploring, failing, reading, and rebuilding turned out to be the most valuable part. There’s still a lot to learn, but this was a solid first step toward really understanding how data moves, transforms, and tells a story (just like this article).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/danielhe4rt/bruin-ecommerce-pipeline" rel="noopener noreferrer"&gt;GitHub Demo: E-commerce Pipeline with Bruin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://getbruin.com/" rel="noopener noreferrer"&gt;Bruin Website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>database</category>
      <category>bruin</category>
      <category>programming</category>
    </item>
    <item>
      <title>Have you used Rust (or Go, or anything else) and just felt relieved by how they treat errors?</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Mon, 31 Mar 2025 16:59:34 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/have-you-used-rust-or-go-or-anything-else-and-just-felt-relieved-by-how-they-treat-errors-3akd</link>
      <guid>https://forem.com/danielhe4rt/have-you-used-rust-or-go-or-anything-else-and-just-felt-relieved-by-how-they-treat-errors-3akd</guid>
      <description>&lt;p&gt;Alright, I need to vent. I've reflecting about engineering recently I swear, exception handling in PHP feels like duct taping over a leaking pipe.&lt;/p&gt;

&lt;p&gt;Like, why is everything so optional? You can throw exceptions, sure, but half the time you're just praying that some function doesn't silently fail or spit out false without context. &lt;/p&gt;

&lt;p&gt;Meanwhile, I’ve been playing with Rust and Go lately and bro... it’s like, it feels safer (?). Every error is explicit. Either it worked (Ok) or it didn’t (Err), and you have to handle it. You don’t get to ignore it and pretend everything’s fine. The compiler literally says: "Nope, go back and deal with it."&lt;/p&gt;

&lt;p&gt;But I feel that do that in PHP would be an Anti-Pattern but at the same time would be safer to work with this type of "Result Objects".&lt;/p&gt;

&lt;h3&gt;
  
  
  With Exceptions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Simulate DB access or something that might throw&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Invalid user ID"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Daniel'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ This will throw&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User name: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Caught exception: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Something went wrong: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMessage&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;h1&gt;
  
  
  With a Result Class
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nv"&gt;$isOk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isOk&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isOk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isOk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RuntimeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Tried to unwrap an Err: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;unwrapOr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$fallback&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;isOk&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$fallback&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getError&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;mixed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// --------------&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Invalid user ID"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Daniel'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isOk&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"User name: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getError&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;I know that the "lack" of generics (annotations solve this partially) makes it harder to accomplish, but I mean, this would improve the whole ecosystem IMHO. &lt;/p&gt;

&lt;p&gt;Also I just started to think about that because recently Microsoft started the revamp/reload/renew of typescript in go and I was wondering: what would be if PHP got a new engine (since Zend Engine is a total mess) with a couple of new features? Would be amazing. &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>php</category>
      <category>programming</category>
      <category>rust</category>
    </item>
    <item>
      <title>How I learn any type of new technology (As a Senior Developer)</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Thu, 20 Mar 2025 19:40:16 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/how-i-learn-any-type-of-new-technology-as-a-senior-developer-47lj</link>
      <guid>https://forem.com/danielhe4rt/how-i-learn-any-type-of-new-technology-as-a-senior-developer-47lj</guid>
      <description>&lt;p&gt;Recently, I had a task of learning a new tool that I had never used or seen anything related to, and I thought: why not write about how I learned it? &lt;/p&gt;

&lt;p&gt;This is the kind of article that teaches you to learn things from a different perspective. Not the best way, but you can reuse some of the concepts written here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Prologue&lt;/li&gt;
&lt;li&gt;
2. The Basics

&lt;ul&gt;
&lt;li&gt;2.1 Break it until you make it&lt;/li&gt;
&lt;li&gt;2.2. But... It's not that obvious&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;3. The Documentation&lt;/li&gt;

&lt;li&gt;4. The Source Code&lt;/li&gt;

&lt;li&gt;5. The Network Tab&lt;/li&gt;

&lt;li&gt;6. The Implementation&lt;/li&gt;

&lt;li&gt;7. Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prologue
&lt;/h2&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%2F5tef8skkj8903ly4c5cr.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%2F5tef8skkj8903ly4c5cr.png" alt="Image description" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I've started a new project (Yet Another Poor SaaS Application) with my friends using PHP and Laravel. The project doesn't really matter, but the &lt;strong&gt;stack&lt;/strong&gt; does. Why is that? Because we're &lt;strong&gt;not rich enough to spend money on self-hosted infrastructure&lt;/strong&gt;, nor on good paid tools... So it's important.&lt;/p&gt;

&lt;p&gt;So, if we're going to build something that has any kind of integration, it needs to &lt;em&gt;at least&lt;/em&gt; have a free tier to consume and not be a &lt;strong&gt;living hell to implement&lt;/strong&gt;. And in thinking about that, we stumbled upon: how are we going to do the user &lt;strong&gt;tracking/metrics&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;My goal is to &lt;strong&gt;show the analytics&lt;/strong&gt; per page of the SaaS user  The average developer might think: we can use &lt;strong&gt;Google Analytics&lt;/strong&gt; and &lt;strong&gt;Google Tag Manager&lt;/strong&gt;, right? Well... Let me tell you something that Chester said once: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I tried so hard and got so far. But in the end, it doesn't even matter - &lt;strong&gt;Chester Bennington&lt;/strong&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dude, I've always been a &lt;strong&gt;Google UI hater&lt;/strong&gt;. But this time it's not for my job but for me and I have no &lt;strong&gt;time to waste&lt;/strong&gt;. So, I spent 4 hours trying to do... the basics of setting it up on my project and understanding how to create a simple tag? And at the end I &lt;strong&gt;wasted my time&lt;/strong&gt; since nothing worked.&lt;/p&gt;

&lt;p&gt;Like, why all Google products have an interface that you need a fucking PhD to use it? Too much information everywhere!&lt;/p&gt;

&lt;p&gt;That's when my friend told me about &lt;strong&gt;PostHog, an open-source analytics platform&lt;/strong&gt; that lets you track user behavior with self-hosted or cloud options (&lt;strong&gt;and beat GTM/GA4 in matter of implementation&lt;/strong&gt;). But at the same time, I'd like to ask you to stay until the end of this article, because it took me some hours and lines of code to do this study.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Basics
&lt;/h2&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%2F5m4qbcst8m3w0adevfe0.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%2F5m4qbcst8m3w0adevfe0.png" alt="Image description" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, this is the most obvious thing, but it has to be said: when you try a new tool, you have to play with every aspect of it. I know we're developers, but the &lt;strong&gt;UI of a product is trying to tell you something&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Break it until you make it
&lt;/h3&gt;

&lt;p&gt;This PostHog process took &lt;strong&gt;infinitely less time to set up&lt;/strong&gt; and that was definitely a plus. However, the UI has too many things happening and my first idea was to try &lt;strong&gt;to click everything&lt;/strong&gt; in and &lt;strong&gt;break the project&lt;/strong&gt; I was on in record time.&lt;/p&gt;

&lt;p&gt;Just think with me: if you're afraid to use a platform/product just because you're in a cloud or "production" environment, you're not going to learn anything in the end.&lt;/p&gt;

&lt;p&gt;At the end of this step, I just deleted the messed up project and started a new one. But at this point, I know how the UI works.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt; DON'T DO IT AT YOUR COMPANY'S CLOUD ACCOUNT, CREATE ONE AND EXPLODE YOUR OWN ENVIRONMENT!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.2 But... It's not that obvious
&lt;/h3&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%2Feir9skvjav9hw72ajsut.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%2Feir9skvjav9hw72ajsut.png" alt="Image description" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok... I have to be honest with you, &lt;strong&gt;sometimes breaking everything is not the answer&lt;/strong&gt; because it's not even an question &lt;strong&gt;depending on the feature you're using&lt;/strong&gt;. At PostHog they have things like &lt;strong&gt;"TrendsQuery", "RetentionQuery", "Web Vitals"&lt;/strong&gt; and a really &lt;strong&gt;fancy UI query builder for each type of query&lt;/strong&gt;. Really impressive! But... I couldn't use it right away.&lt;/p&gt;

&lt;p&gt;Since I have this amazing condition called &lt;strong&gt;ADHD&lt;/strong&gt;, when I see minimally &lt;strong&gt;complex UI's with conditional components&lt;/strong&gt; appearing on the screen, I &lt;strong&gt;just freak out and start panicking&lt;/strong&gt;. But that's no reason to give up, right?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This section is not a criticism of the product, but me getting it out of my chest. Data science is an area of infinite conditional rules, where the more information you have, the more accurate it will be, and I'm taking my first steps to learn it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  3. The Documentation
&lt;/h2&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%2Feszkdwsys3t3js5txyi5.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%2Feszkdwsys3t3js5txyi5.png" alt="Image description" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sure, the documentation! Why haven't I played with this before? I mean, this is the place for developers, right? Right! But we're &lt;strong&gt;developers&lt;/strong&gt; who are going to &lt;strong&gt;use the product&lt;/strong&gt;, so the first step is a must.&lt;/p&gt;

&lt;p&gt;I don't usually go through tutorials, even though I know everyone should. I just don't like it, to me &lt;strong&gt;good API references must tells you everything&lt;/strong&gt;, but what would be everything in my opinion?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Indexable" Title:&lt;/strong&gt;  under a table of contents, this helps a lot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refined Description:&lt;/strong&gt; tells everything that you should know in a first moment to use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation Examples:&lt;/strong&gt; using languages like PHP, JS, Go, Rust and mainly cURL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expected Responses:&lt;/strong&gt; which payload with a "real data" will be served based on the response status (200, 401, 422, 500). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementations Reference:&lt;/strong&gt; Where you can find the actual code to read and understand how things works at the client/server side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Required Scopes:&lt;/strong&gt; Usually you should have scopes for the endpoint.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In most cases you'll have &lt;strong&gt;many elements&lt;/strong&gt; like these which I listed above, but it depends on the API you're using. In my case with this PostHog &lt;strong&gt;specific implementation&lt;/strong&gt;, the challenge is that the &lt;strong&gt;/query/create&lt;/strong&gt; endpoint has a &lt;strong&gt;polymorphic request and response&lt;/strong&gt; and so there's no response payload there.&lt;/p&gt;

&lt;p&gt;So that's when we start digging into the real code because we need to understand how these endpoints works with the actual implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To avoid I could  just write down a &lt;strong&gt;HogQL Query&lt;/strong&gt;, but learning it (for me) would take way more time. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. The Source Code
&lt;/h2&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%2F5oka9gb318g8q967jnbd.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%2F5oka9gb318g8q967jnbd.png" alt="Image description" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We know what we want at this point, right? We want to understand what payload is being sent for each type of request. In my case, I want to understand how &lt;strong&gt;Retention and Trends Query&lt;/strong&gt; works on PostHog. And since the product is open source, I can read it directly from GitHub!&lt;/p&gt;

&lt;p&gt;The front-end is written in &lt;strong&gt;TypeScript&lt;/strong&gt; and the back-end is written in &lt;strong&gt;Python&lt;/strong&gt;. Since I'm a back-end developer, you'd think I'd pick the Python implementation to dig into, right? Well, actually, I'm a Python hater for many reasons. Also, TypeScript gives me a type safety to use as a reference for code search.&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;TypeScript source&lt;/strong&gt; I found the implementation of everything I needed on the client side, but after seeing it I went straight down the rabbit hole and you will understand why.&lt;/p&gt;

&lt;p&gt;Take a look at this snippet &lt;a href="https://github.com/PostHog/posthog/blob/0834410018bc2b7299d8169f828144c5e94b9f9e/frontend/src/queries/schema.ts#L50" rel="noopener noreferrer"&gt;(reference)&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TrendsQuery&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;InsightsQueryBase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TrendsQueryResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NodeKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TrendsQuery&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Granularity of the response. Can be one of `hour`, `day`, `week` or `month`
     *
     * @default day
     */&lt;/span&gt;
    &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;IntervalType&lt;/span&gt;
    &lt;span class="cm"&gt;/** Events and actions to include */&lt;/span&gt;
    &lt;span class="na"&gt;series&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnyEntityNode&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="cm"&gt;/** Properties specific to the trends insight */&lt;/span&gt;
    &lt;span class="nx"&gt;trendsFilter&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;TrendsFilter&lt;/span&gt;
    &lt;span class="cm"&gt;/** Breakdown of the events and actions */&lt;/span&gt;
    &lt;span class="nx"&gt;breakdownFilter&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;BreakdownFilter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can assume a few things: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's an inherited &lt;strong&gt;InsightsQueryBase&lt;/strong&gt;, so other queries have the same base.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;TrendsQueryResponse&lt;/strong&gt; is available and must follow a pattern, so we can check it later.&lt;/li&gt;
&lt;li&gt;The query &lt;strong&gt;"concerns"&lt;/strong&gt; (which you can think of as a &lt;strong&gt;filter&lt;/strong&gt;) isn't as explicit and will require more research.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we need to know what is in the basis and look for the &lt;strong&gt;InsightsQuery Concerns&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="cm"&gt;/** Base class for insight query nodes. Should not be used directly. */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;InsightsQueryBase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;AnalyticsQueryResponseBase&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/** Date range for the query */&lt;/span&gt;
    &lt;span class="nx"&gt;dateRange&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;DateRange&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Exclude internal and test users by applying the respective filters
     *
     * @default false
     */&lt;/span&gt;
    &lt;span class="nx"&gt;filterTestAccounts&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Property filters for all series
     *
     * @default []
     */&lt;/span&gt;
    &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AnyPropertyFilter&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;PropertyGroupFilter&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Groups aggregation
     */&lt;/span&gt;
    &lt;span class="nx"&gt;aggregation_group_type_index&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="cm"&gt;/** Sampling rate */&lt;/span&gt;
    &lt;span class="nx"&gt;samplingFactor&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="cm"&gt;/** Colors used in the insight's visualization */&lt;/span&gt;
    &lt;span class="nx"&gt;dataColorTheme&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="cm"&gt;/** Modifiers used when performing the query */&lt;/span&gt;
    &lt;span class="nx"&gt;modifiers&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;HogQLQueryModifiers&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's the moment you understand that you are &lt;strong&gt;digging in a rabbit hole&lt;/strong&gt; because these &lt;strong&gt;concerns&lt;/strong&gt; seem to be HUGE &lt;strong&gt;objects that grant different behaviors&lt;/strong&gt; within your API. &lt;/p&gt;

&lt;p&gt;After a few hours into it, I started to realize how these concerns affect the query, things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Breakdown:&lt;/strong&gt; More like a a GroupBy clause&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Properties:&lt;/strong&gt; Polymorphic Filtering which totally depends on the query&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Series:&lt;/strong&gt; The type of the data being retrieved (e.g. "views count")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interval:&lt;/strong&gt; a from/to date filtering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is just the &lt;strong&gt;tip of the iceberg&lt;/strong&gt;. There are plenty of other concerns surrounding the many requests on PostHog. But here are the questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there is an &lt;strong&gt;InsightsQueryBase&lt;/strong&gt;, wouldn't these concerns be &lt;strong&gt;shared&lt;/strong&gt; with other types of queries of that category?&lt;/li&gt;
&lt;li&gt;Is there a way for &lt;strong&gt;other types of base queries&lt;/strong&gt; to have the same concerns?&lt;/li&gt;
&lt;li&gt;Should I understand how each type of **concern affects the final query?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I mean, we have to understand. Maybe not that deep, but a general knowledge. But how do we get proof if the documentation doesn't give us examples? &lt;/p&gt;

&lt;p&gt;Well, that's where I explain my favorite thing about a browser: the Network tab!&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The Network Tab
&lt;/h2&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%2F802furxnhzmsfxzkto95.gif" 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%2F802furxnhzmsfxzkto95.gif" alt="Image description" width="2461" height="816"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I just learned all about how to &lt;strong&gt;"explore"&lt;/strong&gt; web applications directly from the browser by doing A-B testing with endpoints. You might think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Depending on the service, you can't build a self-user bot because it may violate the terms of service" - Normal User&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and I would answer that &lt;strong&gt;I couldn't care less&lt;/strong&gt; because I'm doing it for &lt;strong&gt;educational purposes&lt;/strong&gt;. If I'm doing it, it's &lt;strong&gt;to learn how things work&lt;/strong&gt;, &lt;strong&gt;to build my own tools&lt;/strong&gt; and &lt;strong&gt;use their product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Just a random fact: I've been inspecting &lt;strong&gt;elements/requests&lt;/strong&gt; since 2014. My first &lt;strong&gt;"real" GitHub&lt;/strong&gt; project was basically inspecting all &lt;strong&gt;requests from a browser game&lt;/strong&gt; called "TribalWars" and building a &lt;a href="https://github.com/danielhe4rt/tribalwars-bot" rel="noopener noreferrer"&gt;CLI app/bot&lt;/a&gt; to play the game through my terminal with the ultimate goal of not playing it (building a self-bot account).&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%2Fy6l013ho33h8q9ydlhg8.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%2Fy6l013ho33h8q9ydlhg8.png" alt="Image description" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to the PostHog implementation, when I started inspecting, I found &lt;strong&gt;different types of payloads&lt;/strong&gt; for each type of query. With that, I could make &lt;strong&gt;more assumptions&lt;/strong&gt; and use it for the next step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_query_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"54f620e7-fdfe-4749-af41-caed0a3fe671"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"breakdownFilter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"breakdown"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$geoip_country_code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"breakdown_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"event"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"conversionGoal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dateRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"date_from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-7d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"date_to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"filterTestAccounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TrendsQuery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"series"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$pageview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EventsNode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"math"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dau"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pageview"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"trendsFilter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WorldMap"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"refresh"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"async"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the second query just in case :p&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"client_query_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"25d4b82f-5bbe-4665-89a7-7aedcc7b103e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dateRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"date_from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-7d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"date_to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"filterTestAccounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RetentionQuery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"retentionFilter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"period"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Week"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"retentionReference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"retentionType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"retention_first_time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"totalIntervals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"refresh"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"async"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would include the results query, but that would be too much code and the point of this section is already made. Now it's time to finish this entire flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The Implementation
&lt;/h2&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%2F2xyafxt7vjni7tvg3w0z.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%2F2xyafxt7vjni7tvg3w0z.png" alt="Image description" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's when you start thinking, "Does the tooling available meet my needs? If the SDK doesn't give me a fully typed API, I'd rather build my own stuff.  I mean, I like to do things from &lt;strong&gt;TOTALLY SCRATCH&lt;/strong&gt;! Yeah, the whole reinventing the wheel thing, you know?&lt;/p&gt;

&lt;p&gt;The reason is simple: I'm a developer who learns how things work by rebuilding them and observing &lt;strong&gt;how they behave&lt;/strong&gt;. And with that, I decided to build a &lt;strong&gt;PostHog Dedicated Query Builder with PHP&lt;/strong&gt; to learn how things work on my end.&lt;/p&gt;

&lt;p&gt;So far this is what I've got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have multiple query types; &lt;/li&gt;
&lt;li&gt;These queries can inherit properties/concerns but not necessarily use all of them; &lt;/li&gt;
&lt;li&gt;Queries share filters/concerns;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how do we organize it? And after hours of digging in the &lt;strong&gt;Source&lt;/strong&gt; and &lt;strong&gt;Network&lt;/strong&gt; tabs, this was my answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;------
- QueryBuilder Feature at my own PostHogSDK
------

Query
├── Builders
│   ├── AbstractQueryBuilder.php
│   └── Insights
│       ├── AbstractInsightsQueryBuilder.php
│       ├── RetentionQueryBuilder.php
│       └── TrendsQueryBuilder.php
├── Filters
│   ├── Breakdown
│   │   ├── BreakdownFilter.php
│   │   ├── BreakdownTypeEnum.php
│   │   └── Concerns
│   │       └── InteractsWithBreakdown.php
│   ├── Compare
│   │   ├── CompareFilter.php
│   │   └── Concerns
│   │       └── InteractsWithCompare.php
│   ├── ConversionGoal
│   │   ├── ActionConversionGoal.php
│   │   ├── Concern
│   │   │   └── InteractsWithConversionGoal.php
│   │   ├── Contracts
│   │   │   └── ConversionGoalContract.php
│   │   └── CustomEventConversionGoal.php
│   ├── DateRange
│   │   ├── Concerns
│   │   │   └── InteractsWithDateRange.php
│   │   └── DateRangeFilter.php
│   ├── Interval
│   │   ├── Concerns
│   │   │   └── InteractsWithInterval.php
│   │   └── QueryIntervalEnum.php
│   ├── Node
│   │   ├── ActionNode.php
│   │   ├── Concerns
│   │   │   ├── InteractsWithMath.php
│   │   │   └── InteractsWithSeries.php
│   │   ├── Contracts
│   │   │   └── EntityNodeContract.php
│   │   ├── EntityNodeKindEnum.php
│   │   ├── EntityNode.php
│   │   ├── EventsNode.php
│   │   └── MathEnum.php
│   ├── Properties
│   │   ├── BaseProperty.php
│   │   ├── Concerns
│   │   │   └── InteractsWithProperties.php
│   │   ├── Contracts
│   │   │   └── PropertyFilterContract.php
│   │   ├── Filters
│   │   │   ├── EventPropertyFilter.php
│   │   │   └── SessionPropertyFilter.php
│   │   ├── PropertyFilterKind.php
│   │   └── PropertyOperator.php
│   └── Retention
│       ├── Concerns
│       │   └── InteractsWithRetention.php
│       ├── Enums
│       │   ├── RetentionPeriodEnum.php
│       │   ├── RetentionReferenceEnum.php
│       │   └── RetentionTypeEnum.php
│       └── RetentionFilter.php
├── QueryBuilderInterface.php
├── QueryFactory.php
└── QueryKindEnum.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every filter has your own dedicated spot, where it can be inherited to any type of builder using &lt;strong&gt;PHP Traits&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;InteractsWithDateRange&lt;/span&gt;  
&lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;?DateRangeFilter&lt;/span&gt; &lt;span class="nv"&gt;$dateRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setDateRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;DateRangeFilter&lt;/span&gt; &lt;span class="nv"&gt;$dateRange&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dateRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$dateRange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getDateRange&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;?DateRangeFilter&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dateRange&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;buildDateRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dateRange&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'dateRange'&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="s1"&gt;'date_from'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dateRange&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'date_to'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;dateRange&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="p"&gt;];&lt;/span&gt;        
        &lt;span class="p"&gt;}&lt;/span&gt;    
    &lt;span class="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;So the only requirement of a query builder is to have the &lt;strong&gt;"build()"&lt;/strong&gt; method provided by my &lt;strong&gt;QueryBuilderContract&lt;/strong&gt;, so I can ensure that at least the typing will be satisfied at the end. Each use in the class below is a different common QueryBuilder concern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrendsQueryBuilder&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractInsightsQueryBuilder&lt;/span&gt;  
&lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;InteractsWithInterval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;InteractsWithDateRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;InteractsWithBreakdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;InteractsWithCompare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;InteractsWithConversionGoal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;InteractsWithProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="nc"&gt;InteractsWithSeries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;QueryKindEnum&lt;/span&gt; &lt;span class="nv"&gt;$queryType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;QueryKindEnum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;TrendsQuery&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  


    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;jsonSerialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;jsonSerialize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;  
    &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="nv"&gt;$payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;jsonSerialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  

        &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'kind'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;queryType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildDateRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildProperties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildConversionGoal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildBreakdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we are coding, we have to pay double attention to the minimal details around the implementation that is being made. And frankly, when I build this kind of tool, I mostly think that someone will use it, which raises the attention bar even higher.&lt;/p&gt;

&lt;p&gt;The end result of this study is a fully functional &lt;strong&gt;Trends&lt;/strong&gt; and &lt;strong&gt;Retention&lt;/strong&gt; &lt;strong&gt;QueryBuilder&lt;/strong&gt; for the PostHog API's:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'can build a retention query'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nv"&gt;$expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="s2"&gt;"kind"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"RetentionQuery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s2"&gt;"dateRange"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
            &lt;span class="s2"&gt;"date_from"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"-7d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="s2"&gt;"date_to"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;  
        &lt;span class="p"&gt;],&lt;/span&gt;  
        &lt;span class="s2"&gt;"filterTestAccounts"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s2"&gt;"retentionFilter"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
            &lt;span class="s2"&gt;"retentionType"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"retention_first_time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="s2"&gt;"retentionReference"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="s2"&gt;"totalIntervals"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="s2"&gt;"period"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Week"&lt;/span&gt;  
        &lt;span class="p"&gt;]&lt;/span&gt;  
    &lt;span class="p"&gt;];&lt;/span&gt;  
    &lt;span class="nv"&gt;$queryBuilder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RetentionQueryBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setDateRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DateRangeFilter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-7d'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setRetention&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionFilter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;weekly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setRetentionType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionTypeEnum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FIRST_TIME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setRetentionReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionReferenceEnum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="p"&gt;);&lt;/span&gt;  
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queryBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toBeInstanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetentionQueryBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$queryBuilder&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toMatchArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'can build a trends-query'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nv"&gt;$expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
        &lt;span class="s1"&gt;'kind'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'TrendsQuery'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s1"&gt;'filterTestAccounts'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s1"&gt;'dateRange'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
            &lt;span class="s1"&gt;'date_from'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'-7d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="s1"&gt;'date_to'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="p"&gt;],&lt;/span&gt;        
        &lt;span class="s1"&gt;'interval'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'day'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="s1"&gt;'series'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
            &lt;span class="p"&gt;[&lt;/span&gt;                
                &lt;span class="s1"&gt;'event'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'$pageview'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'kind'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'EventsNode'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'math'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'dau'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Pageview'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="p"&gt;],&lt;/span&gt;        
        &lt;span class="p"&gt;],&lt;/span&gt;        
            &lt;span class="s1"&gt;'compareFilter'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
            &lt;span class="s1"&gt;'compare'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="p"&gt;],&lt;/span&gt;        
        &lt;span class="s1"&gt;'properties'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
            &lt;span class="p"&gt;[&lt;/span&gt;                &lt;span class="s1"&gt;'type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'event'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'key'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'$host'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'operator'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'exact'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
                &lt;span class="s1"&gt;'value'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'api-main-ofjibb.laravel.cloud'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
            &lt;span class="p"&gt;],&lt;/span&gt;        
        &lt;span class="p"&gt;],&lt;/span&gt;    
    &lt;span class="p"&gt;];&lt;/span&gt;  
    &lt;span class="nv"&gt;$actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TrendsQueryBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setDateRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DateRangeFilter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'-7d'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;QueryIntervalEnum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Day&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addCompareFilter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addSeries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EventsNode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$pageview'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MathEnum&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DAU&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Pageview'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EventPropertyFilter&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'$host'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PropertyOperator&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Exact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'api-main-ofjibb.laravel.cloud'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  


    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toBeInstanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TrendsQueryBuilder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$actual&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;toMatchArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expected&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;You can check the Pull Request for this implementation &lt;a href="https://github.com/danielhe4rt/posthog-php-laravel-sdk/pull/1" rel="noopener noreferrer"&gt;clicking here&lt;/a&gt;. Feel free to contribute on this project too!&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Conclusion
&lt;/h2&gt;

&lt;p&gt;This is just a &lt;strong&gt;study&lt;/strong&gt; in the PostHog API that I &lt;strong&gt;enjoyed a lot and decided to write about&lt;/strong&gt;. Building things from &lt;strong&gt;scratch and doing proper research&lt;/strong&gt; is something that can help you &lt;strong&gt;learn things on another level&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now I can tell you that I can play with the PostHog platform in a &lt;strong&gt;really smooth way&lt;/strong&gt;, &lt;strong&gt;without the worries mentioned in the first section&lt;/strong&gt; of this article since &lt;strong&gt;I just breaked it once, divided concerns and studied each of them separately&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This approach—&lt;strong&gt;breaking things&lt;/strong&gt;, &lt;strong&gt;diving into the docs&lt;/strong&gt;, &lt;strong&gt;exploring the network tab&lt;/strong&gt;, and &lt;strong&gt;rebuilding from scratch&lt;/strong&gt;—can be applied to &lt;strong&gt;any technology&lt;/strong&gt;. Whether it's &lt;strong&gt;PostHog&lt;/strong&gt;, a new API, or a framework, &lt;strong&gt;understanding the internals makes you a better developer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's it! Hope you enjoyed and don't forget to drink water!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Fri, 21 Feb 2025 16:48:40 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/-20gf</link>
      <guid>https://forem.com/danielhe4rt/-20gf</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/camilacodes" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F719040%2F7b71d94f-6745-4d23-855f-03be53978d2e.jpg" alt="camilacodes"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/camilacodes/devops-para-noobs-3-boas-praticas-para-bancos-de-dados-para-compartilhar-com-os-devs-aws-rds-cgo" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;#DevOps para noobs - 3 Boas Práticas de Bancos de Dados para compartilhar com os Devs (AWS RDS)&lt;/h2&gt;
      &lt;h3&gt;Camila Figueira ・ Feb 20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>devops</category>
      <category>database</category>
      <category>aws</category>
    </item>
    <item>
      <title>This is all what I've learned about Go in TWO Weeks!</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Fri, 25 Oct 2024 21:38:22 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/this-is-all-what-ive-learned-about-go-in-two-weeks-1bf2</link>
      <guid>https://forem.com/danielhe4rt/this-is-all-what-ive-learned-about-go-in-two-weeks-1bf2</guid>
      <description>&lt;p&gt;What is your approach when you need to learn something new? I have a very specific one and once again I tested it while learning Golang!&lt;/p&gt;

&lt;p&gt;There's too much content to talk about, but my aim here is to list things that I found useful and that I specifically took the time to learn properly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Prologue&lt;/li&gt;
&lt;li&gt;
2. Meet the CLI

&lt;ul&gt;
&lt;li&gt;2.1 CLI: go mod&lt;/li&gt;
&lt;li&gt;2.2 CLI: go run&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

3. Comparing Different Syntax's

&lt;ul&gt;
&lt;li&gt;3.1 Syntax: Classes/Structs and the API Encapsulation&lt;/li&gt;
&lt;li&gt;3.2 Syntax: Interface Implementation is WEIRD AS FUC*&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

4. Stdlib: definitely an AWESOME toolkit

&lt;ul&gt;
&lt;li&gt;4.1 Packages: Primitive Types&lt;/li&gt;
&lt;li&gt;4.2 Packages: Useful Stuff&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

5. Tests in Go are THAT SIMPLE

&lt;ul&gt;
&lt;li&gt;5.1 Tests: Basic Testing&lt;/li&gt;
&lt;li&gt;5.2 Tests: Jetbrains Boilerplate&lt;/li&gt;
&lt;li&gt;5.3 Tests: Running Tests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;6. Beware Cyclic Imports&lt;/li&gt;

&lt;li&gt;7. Defer this, defer that... But, what is a Defer?&lt;/li&gt;

&lt;li&gt;8. Error Management for Noobs&lt;/li&gt;

&lt;li&gt;9. Conclusion feat: Low Latency Coding Challenge&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prologue
&lt;/h2&gt;

&lt;p&gt;For the last 2 weeks I've been learning and building small applications with Golang. At the moment it's been almost 50h of code through many livestreams and it's been pretty awesome to learn something that I previously had a some small issues with the language.&lt;/p&gt;

&lt;p&gt;In this two weeks journey I've crafted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A small and REALLY simple shell &lt;/li&gt;
&lt;li&gt;A Redis Basic implementation&lt;/li&gt;
&lt;li&gt;HTTP 1.1 protocol implementation&lt;/li&gt;
&lt;li&gt;A DNS server implementation&lt;/li&gt;
&lt;li&gt;and a job test for a really cool company (which will be available at the end of this article).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And all this because my boss asked me, once again, to learn a new technology to work on some &lt;strong&gt;ScyllaDB&lt;/strong&gt; PoC's and demos... I wasn't too happy with the decision, but well, it's my job. &lt;/p&gt;

&lt;p&gt;During the last year I've been studying Rust, and it's probably still too complex for me, but I've learnt some really cool concepts that made my switch to Go work like a charm! &lt;/p&gt;

&lt;p&gt;In this article I'll give you some tips and advice to speed up your learning flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Meet the CLI
&lt;/h2&gt;

&lt;p&gt;I'm a PHP developer and I'm used to the BEST CLI ever made (yes, it's Artisan), however through my journey as a developer I've been through awesome projects many of which have been..:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cargo (Rust)&lt;/li&gt;
&lt;li&gt;NPM (JS)&lt;/li&gt;
&lt;li&gt;Composer (PHP)&lt;/li&gt;
&lt;li&gt;and so on...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I got to the Go environment, it started as a real problem. At least for me, the developer experience of Golang in terms of tools and documentation could be much better. Thinking about this, I decided to go through 3 commands that you &lt;strong&gt;HAVE TO LEARN&lt;/strong&gt; at the beginning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember: this is just a walkthrough with my own explanation of things. If you want detailed information, open the docs :)&lt;br&gt;
Also: go docs sucks please someone put a syntax highlighter there&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.1 CLI:  go mod
&lt;/h3&gt;

&lt;p&gt;Depending on whether you want to modularise your application or have an organised environment, this will be the most useful command at first.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;go mod&lt;/code&gt; command manages all the dependencies within your project and also takes care of &lt;code&gt;autoremoving&lt;/code&gt; anything that's no longer used.&lt;/p&gt;

&lt;p&gt;First, inside your new empty folder, let's init a new module inside the project with &lt;code&gt;go mod init&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;go-fodase
&lt;span class="nb"&gt;cd &lt;/span&gt;go-fodase

&lt;span class="c"&gt;# go mod init &amp;lt;module-name&amp;gt;&lt;/span&gt;
go mod init github.com/danielhe4rt/go-fodase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new file in the project root called &lt;code&gt;go.mod&lt;/code&gt;, which is basically the contents at the moment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The module name&lt;/li&gt;
&lt;li&gt;Your Go version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the file, if you want to check it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# folder: ~/go-fodase&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;go.mod

&lt;span class="c"&gt;# module github.com/danielhe4rt/gofodase&lt;/span&gt;
&lt;span class="c"&gt;# &lt;/span&gt;
&lt;span class="c"&gt;# go 1.23.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the next thing I really liked was the &lt;code&gt;go mod tidy&lt;/code&gt;, which basically adds any missing dependencies and removes unused ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go mod tidy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This second one is just to keep into your mind that this exists and it's really useful! Probably your environment will run it EVERY TIME and you will get used to see imports vanishing :p&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2.2 CLI: go run
&lt;/h3&gt;

&lt;p&gt;This is probably the most common command you'll use, since you HAVE to run your project, but here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You should point to the file that contains the &lt;code&gt;main()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;This file doesn't have to be in the root of your folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important thing to remember about this command is that when you run the &lt;code&gt;go run&lt;/code&gt; command, it will look for the &lt;code&gt;go.mod&lt;/code&gt; file in your current directory and use it as the basis for mapping your whole project (imports, packages, etc). Here's some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# go run &amp;lt;your-main-file&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# Environment 1&lt;/span&gt;
&lt;span class="c"&gt;# .&lt;/span&gt;
&lt;span class="c"&gt;# ├── go.mod&lt;/span&gt;
&lt;span class="c"&gt;# └── main.go&lt;/span&gt;
go run app.go

&lt;span class="c"&gt;# Environment 2&lt;/span&gt;
&lt;span class="c"&gt;# .&lt;/span&gt;
&lt;span class="c"&gt;# ├── go.mod&lt;/span&gt;
&lt;span class="c"&gt;# └── src&lt;/span&gt;
&lt;span class="c"&gt;#     └── main.go&lt;/span&gt;
go run src/app.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's our &lt;code&gt;app.go&lt;/code&gt; content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"whats up! don't forget to like this article &amp;lt;3"&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;Now you know the basics to execute an project! Literally, hello world! &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Comparing Different Syntax's:
&lt;/h2&gt;

&lt;p&gt;My problem with Go has always been the way it's written, but after hours of coding I realised that it's simpler than I thought. As you might have guessed, I have a strong background in PHP and some experience with Rust. &lt;/p&gt;

&lt;p&gt;When I started to learn Rust in 2023, fortunately a guy I'm a big fan of, &lt;a href="https://github.com/nunomaduro" rel="noopener noreferrer"&gt;Nuno Maduro (Laravel)&lt;/a&gt;, gave a talk called &lt;a href="https://www.youtube.com/watch?v=q_9WErUNpKU" rel="noopener noreferrer"&gt;"PHP for Rust Developers"&lt;/a&gt;, which gave me some basic &lt;strong&gt;introduction to the syntax&lt;/strong&gt; and gave me some breathing space while I was completely &lt;strong&gt;STOMPED by Rust&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Anyway, it was useful to me at the time, so why not do some comparisons? &lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Syntax: Classes/Structs and the API Encapsulation
&lt;/h3&gt;

&lt;p&gt;In OOP we have classes, which is a really cool way of abstracting your code into small pieces, and you have something "like that". Golang can be seen as an &lt;strong&gt;odyssey&lt;/strong&gt;, because it can be an epic development to turn the environment into whatever you want it to be.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember, &lt;strong&gt;Golang&lt;/strong&gt; is a "high level language" that provides a "system level" syntax that allows you to easily work with "low level" implementations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Under the Go syntax, you can &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[Struct] Define a struct by prefixing it with &lt;code&gt;type&lt;/code&gt;, adding your "class/struct" name and then adding a suffix of &lt;code&gt;struct&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[Encapsulation] Define the exposure of your class/structure related elements by starting them with &lt;strong&gt;UpperCase&lt;/strong&gt; or &lt;strong&gt;LowerCase&lt;/strong&gt; names.

&lt;ul&gt;
&lt;li&gt;[Visibility: "public"]: Set the item name to uppercase.&lt;/li&gt;
&lt;li&gt;[Visibility: "private/protected"]: Set the item name in lower case.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And you can use it for: &lt;code&gt;Structs&lt;/code&gt;, &lt;code&gt;Struct Fields&lt;/code&gt;, &lt;code&gt;Struct Methods&lt;/code&gt;. Take a closer look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// -----------------------&lt;/span&gt;
&lt;span class="c"&gt;// file: src/users/user.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="c"&gt;// starts with uppercase: public&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt;  &lt;span class="kt"&gt;uint8&lt;/span&gt;  &lt;span class="c"&gt;// starts with uppercase: public&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="c"&gt;// Starts with lowercase: private&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="c"&gt;// Starts with uppercase: public&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Greetings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;cheering&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Don't forget to follow me back!"&lt;/span&gt;

    &lt;span class="c"&gt;// Can consume same struct functions.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hey, %v (%v)! %v !"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cheering&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 


&lt;span class="c"&gt;// -----------------&lt;/span&gt;
&lt;span class="c"&gt;// file: src/main.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;  

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"github.com/danielhe4rt/go-fodase/src/users"&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="c"&gt;// ❌ You CAN'T start 'name'. Use a Setter Function for it.    &lt;/span&gt;
    &lt;span class="c"&gt;// user := users.User{    &lt;/span&gt;
    &lt;span class="c"&gt;//     name: "danielhe4rt", // ❌&lt;/span&gt;
    &lt;span class="c"&gt;//     Age:  25,            // ✅&lt;/span&gt;
    &lt;span class="c"&gt;// }&lt;/span&gt;

    &lt;span class="c"&gt;// ✅ Now you're only initializing what you need.    &lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  

    &lt;span class="c"&gt;// Methods Calls  &lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"danielhe4rt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// ✅&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;              &lt;span class="c"&gt;// ❌&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Greetings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;            &lt;span class="c"&gt;// ✅&lt;/span&gt;

    &lt;span class="n"&gt;currentName&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// ❌ &lt;/span&gt;
    &lt;span class="n"&gt;currentAge&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;     &lt;span class="c"&gt;// ✅ &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Rust, you have an more explicit approach (more oop like languages) where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[Struct] Define an struct using the prefix &lt;code&gt;struct&lt;/code&gt;, adding your "Class/Struct" name and that's it.&lt;/li&gt;
&lt;li&gt;[Encapsulation] If you want something to be public to other "crates", you should add the &lt;code&gt;pub&lt;/code&gt; prefix in the part of the code you want to expose.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// file: src/users/mod.rs&lt;/span&gt;

&lt;span class="c1"&gt;// Make the struct `User` public&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Private field: accessible only within the `users` module&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Public field: accessible from other modules&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Public method to create a new User with a name and age&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// Initialize with an empty name&lt;/span&gt;
            &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Public setter method to set the private `name` field&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;set_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Private method to get the name&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Public method that uses both public and private fields/methods&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cheering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Don't forget to follow me back!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"Hey, {} ({} years old)! {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get_name&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;cheering&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// file: src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;users&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ❌ You CAN'T directly set the private `name` field&lt;/span&gt;
    &lt;span class="c1"&gt;// let user = User {&lt;/span&gt;
    &lt;span class="c1"&gt;//     name: String::from("danielhe4rt"), // ❌&lt;/span&gt;
    &lt;span class="c1"&gt;//     age: 25,                           // ✅&lt;/span&gt;
    &lt;span class="c1"&gt;// };&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Initialize the User using the constructor&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;User&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Use the setter method to set the private `name`&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="nf"&gt;.set_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"danielhe4rt"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="nf"&gt;.greetings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// ✅ Call the public `greetings` method&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;current_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="py"&gt;.age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// ✅ Access the public `age` field directly&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;current_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c1"&gt;// ❌ You CAN'T access the private `name` field directly&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;current_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="nf"&gt;.get_name&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ❌ You CAN'T call the private `get_name` method directly&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'd like to make things explicit like PHP, Java and so on but if you stop to think is &lt;em&gt;LESS CODE&lt;/em&gt; to write, but it also impacts the readability.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Syntax: Interface Implementation is WEIRD AS FUC*
&lt;/h3&gt;

&lt;p&gt;To be really honest, I'm the kind of person who would try to put, I don't know... LARAVEL in Go Environment, but that was already done in &lt;a href=""&gt;Goravel&lt;/a&gt;. Anyway, I really like the idea of working with &lt;strong&gt;"Interface/Contract Driven Development",&lt;/strong&gt; and for the first time I got stuck with it in a language.&lt;/p&gt;

&lt;p&gt;In Go, interfaces aren't &lt;strong&gt;"implemented"&lt;/strong&gt; in a structure/class, and for an OOP guy like me, it's just crazy to have such a design decision fit into my head. Have a look at what is expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OAuthContract&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GithubOAuthProvider&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;OAuthContract&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpotifyAuthProvider&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;OAuthContract&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$routeProvider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;OAuthContract&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;'github'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GithubOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="s1"&gt;'spotify'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SpotifyAuthProvider&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;OAuthProviderException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;notFound&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when it comes to go: you don't have this explicit implementation of an "interface" inside a structure, and that's, hmm... &lt;strong&gt;weird&lt;/strong&gt;? Instead, you just implement the interface's required methods, which go will check for you at compile time. It's fair to know that this is a compiled language and it should never be a problem, but I'm talking about my perspective with &lt;strong&gt;Developer Experience&lt;/strong&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"errors"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;OAuthContract&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;Authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// GithubOAuthProvider implements the OAuthContract interface for GitHub.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;GithubOAuthProvider&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c"&gt;// Redirect handles the redirection logic for GitHub OAuth.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;GithubOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Implement GitHub-specific redirection logic here.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Authenticate handles the authentication logic for GitHub OAuth.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;GithubOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Implement GitHub-specific authentication logic here.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// SpotifyOAuthProvider implements the OAuthContract interface for Spotify.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SpotifyOAuthProvider&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c"&gt;// Redirect handles the redirection logic for Spotify OAuth.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SpotifyOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Implement Spotify-specific redirection logic here.&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Redirecting to Spotify with code: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Authenticate handles the authentication logic for Spotify OAuth.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SpotifyOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Implement Spotify-specific authentication logic here.&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authenticating Spotify token: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// AuthenticateFactory is a factory function that returns an instance of OAuthContract&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AuthenticateFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OAuthContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"github"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GithubOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"spotify"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;SpotifyOAuthProvider&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;OAuthProviderError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In any case, with some time coding in the language you will get used with it. Now, let's talk about what the base environment offers to you without download anything!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Stdlib: definitely an AWESOME toolkit
&lt;/h2&gt;

&lt;p&gt;Now I'm talking about everything that Go serves you with the &lt;strong&gt;Standard Library&lt;/strong&gt;, without download an third party package. Here's some chronological timeline for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1st day:&lt;/strong&gt; WHAT? WHY NOT LIKE JS/Java IN THE MATTER THAT THE TYPE CARRIES ALL METHODS? (And I hate both of them)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1st week:&lt;/strong&gt; Wait, maybe that's good shit (after understand the packages for primitive types)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2nd week:&lt;/strong&gt; WHAT? WHY NOT OTHER LANGS HAVE SUCH A GOOD LIBRARIES BY DEFAULT?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not joking about that, every day that I explore go I found some cool library under the standard ones. So, let's start talking about primitive types.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 Packages: Primitive Types
&lt;/h3&gt;

&lt;p&gt;Like PHP, and &lt;strong&gt;unlike&lt;/strong&gt; many other languages (Rust, Java, JS, etc), Golang needs &lt;strong&gt;"helper"&lt;/strong&gt; functions to perform most of the related &lt;strong&gt;type operations&lt;/strong&gt;. We can think of them as "anemic" types, since they don't have "utility" attached to them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PHP Example (with a REALLY UGLY API)&lt;/span&gt;
&lt;span class="c1"&gt;// String manipulation using built-in PHP functions&lt;/span&gt;
&lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Check if the string contains a substring&lt;/span&gt;
&lt;span class="nv"&gt;$contains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Contains 'World': "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$contains&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Output: true&lt;/span&gt;

&lt;span class="c1"&gt;// Convert the string to uppercase&lt;/span&gt;
&lt;span class="nv"&gt;$upper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtoupper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Uppercase: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$upper&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Output: HELLO, WORLD!&lt;/span&gt;

&lt;span class="c1"&gt;// Split the string by comma&lt;/span&gt;
&lt;span class="nv"&gt;$split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Split by comma: "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;print_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$split&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: Array ( [0] =&amp;gt; Hello  [1] =&amp;gt;  World! )&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you're working with a &lt;strong&gt;"String" type&lt;/strong&gt;, you have other packages like &lt;code&gt;strconv&lt;/code&gt; or &lt;code&gt;strings&lt;/code&gt; to manipulate it! But here's a golden rule to never forget which package to look at: if your type is &lt;code&gt;string&lt;/code&gt;, look for the same package with a pluralised name! &lt;/p&gt;

&lt;p&gt;In a nutshell, this will give you functions related to &lt;code&gt;[]Type&lt;/code&gt; and &lt;code&gt;Type&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;String type&lt;/strong&gt; -&amp;gt; &lt;code&gt;import ("strings")&lt;/code&gt; for operations like: &lt;strong&gt;Contains()&lt;/strong&gt;, &lt;strong&gt;Upper()&lt;/strong&gt;, &lt;strong&gt;Split()&lt;/strong&gt; ...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bytes type&lt;/strong&gt; -&amp;gt; &lt;code&gt;import ("bytes")&lt;/code&gt; for operations like &lt;strong&gt;Include()&lt;/strong&gt;, &lt;strong&gt;Compare()&lt;/strong&gt;, &lt;strong&gt;Split()&lt;/strong&gt; ...&lt;/li&gt;
&lt;li&gt;and so on!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take a look at the code, so you can validate by yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// String manipulation using the "strings" package&lt;/span&gt;
    &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;

    &lt;span class="c"&gt;// Check if the string contains a substring&lt;/span&gt;
    &lt;span class="n"&gt;contains&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Contains 'World': %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: true&lt;/span&gt;

    &lt;span class="c"&gt;// Convert the string to uppercase&lt;/span&gt;
    &lt;span class="n"&gt;upper&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToUpper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Uppercase: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: HWith this intELLO, WORLD!&lt;/span&gt;

    &lt;span class="c"&gt;// Split the string by comma&lt;/span&gt;
    &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Split by comma: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Output: [Hello  World!]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's supposed to be simple, but I struggled with that for a while until gets into my head. Maybe using Laravel and their helper functions for too many years made me forget how tough is to code without a Framework :D &lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Packages: Useful Stuff
&lt;/h3&gt;

&lt;p&gt;While I was exploring tools and projects, I got a really good introduction to many projects and I'd like to list each of them and the libs I've used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build your own Shell Challenge:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;packages:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;fmt:&lt;/strong&gt; I/O library (Scan/Read and Write stuff on your screen)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;os:&lt;/strong&gt; functions and helpers that talks directly with your Operational System.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;strconv&lt;/strong&gt;: cast specific data-types to string or cast string to any defined type.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Build your own (HTTP|DNS) Server Challenge:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;packages:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;net:&lt;/strong&gt; integration layer with network I/O protocols such as HTTP, TCP, UDP and Unix Domain Sockets&lt;/li&gt;
&lt;li&gt;[previous packages...]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Mid Level Homework Task assignment?

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;packages:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;flag:&lt;/strong&gt; Captures your CLI arguments into variables &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;log:&lt;/strong&gt; Adds Log's channels to your application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;crypto/rand:&lt;/strong&gt; Secure Cryptographic Random Generator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;math/rand:&lt;/strong&gt; Math Numbers Random Generator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;time:&lt;/strong&gt; Duration/Time Lib&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Here's a &lt;strong&gt;scrollable view&lt;/strong&gt; of all the package implementations so you can check them out. There are PLENTY of cool std packages that can be cited here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ATTENTION: that's a LOT OF CODE! :p&lt;br&gt;
Don't forget to comment your favorite features (besides goroutines and channels) :p&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;crypto&lt;/span&gt; &lt;span class="s"&gt;"crypto/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/hex"&lt;/span&gt;
    &lt;span class="s"&gt;"flag"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 1: fmt Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// fmtExample demonstrates basic input and output operations using the fmt package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fmtExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== fmt Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;

    &lt;span class="c"&gt;// Prompt the user for their name&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter your name: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scanln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error reading name:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Prompt the user for their age&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter your age: "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scanln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error reading age:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Display the collected information&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s! You are %d years old.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;besides&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 2: os Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// osExample showcases how to interact with the operating system, such as reading environment variables and exiting the program.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;osExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== os Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Retrieve the HOME environment variable&lt;/span&gt;
    &lt;span class="n"&gt;home&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HOME"&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;home&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HOME environment variable not set."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Exit the program with a non-zero status code to indicate an error&lt;/span&gt;
        &lt;span class="c"&gt;// Uncomment the next line to enable exiting&lt;/span&gt;
        &lt;span class="c"&gt;// os.Exit(1)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Your home directory is: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Demonstrate exiting the program successfully&lt;/span&gt;
    &lt;span class="c"&gt;// Uncomment the next lines to enable exiting&lt;/span&gt;
    &lt;span class="c"&gt;/*
        fmt.Println("Exiting program with status code 0.")
        os.Exit(0)
    */&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 3: strconv Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// strconvExample demonstrates converting between strings and other data types.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;strconvExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== strconv Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Convert string to integer&lt;/span&gt;
    &lt;span class="n"&gt;numStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"456"&lt;/span&gt;
    &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error converting string to int:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Converted string '%s' to integer: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Convert integer back to string&lt;/span&gt;
    &lt;span class="n"&gt;newNumStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Converted integer %d back to string: '%s'&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newNumStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 4: net Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// netExample demonstrates making a simple HTTP GET request using the net package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;netExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== net Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Make an HTTP GET request to a public API&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.github.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error making HTTP GET request:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Display the HTTP status code&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response Status: %s&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 5: flag Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// flagExample demonstrates how to capture command-line arguments using the flag package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;flagExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== flag Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Define command-line flags&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"a name to say hello to"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"your age"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Parse the flags&lt;/span&gt;
    &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Use the flag values&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, %s!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You are %d years old.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 6: log Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// logExample demonstrates logging messages to a file using the log package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;logExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== log Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Open or create a log file&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpenFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"app.log"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_CREATE&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_WRONLY&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_APPEND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to open log file: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Set the log output to the file&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Log messages&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Application started"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Logging an event at %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"some point"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Application finished"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Logs have been written to app.log&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 7: crypto/rand Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// cryptoRandExample demonstrates generating a secure random string using the crypto/rand package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;cryptoRandExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== crypto/rand Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Generate a secure random string of 16 bytes (32 hex characters)&lt;/span&gt;
    &lt;span class="n"&gt;randomStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;generateSecureRandomString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error generating secure random string:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Secure Random String:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;randomStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// generateSecureRandomString generates a hexadecimal string of the specified byte length using crypto/rand.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;generateSecureRandomString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;crypto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 8: math/rand Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// mathRandExample demonstrates generating pseudo-random numbers and shuffling a slice using the math/rand package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;mathRandExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== math/rand Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Seed the random number generator to ensure different outputs each run&lt;/span&gt;
    &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c"&gt;// Generate a random integer between 0 and 99&lt;/span&gt;
    &lt;span class="n"&gt;randomInt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Random integer (0-99): %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Generate a random float between 0.0 and 1.0&lt;/span&gt;
    &lt;span class="n"&gt;randomFloat&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Float64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Random float (0.0-1.0): %f&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;randomFloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Shuffle a slice of integers&lt;/span&gt;
    &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shuffled slice: %v&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Example 9: time Package&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="c"&gt;// timeExample demonstrates working with current time, formatting, parsing, sleeping, and measuring durations using the time package.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;timeExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"=== time Package Example ==="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Current time&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Current time:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Formatting time&lt;/span&gt;
    &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02 15:04:05"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Formatted time:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formatted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Parsing time from a string&lt;/span&gt;
    &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2006-01-02"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"2024-10-25"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error parsing time:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Parsed time:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Sleep for 2 seconds&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleeping for 2 seconds..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Awake!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Measuring duration&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Elapsed time: %s&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elapsed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// =========================&lt;/span&gt;
&lt;span class="c"&gt;// Main Function&lt;/span&gt;
&lt;span class="c"&gt;// =========================&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Execute each example function sequentially&lt;/span&gt;
    &lt;span class="n"&gt;fmtExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;osExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;strconvExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;netExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;flagExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;logExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;cryptoRandExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mathRandExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;timeExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All examples executed."&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;Seriously, that's just amazing! So, lets keep going for tests now.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Tests in Go are THAT SIMPLE
&lt;/h2&gt;

&lt;p&gt;In my second project using Go, I saw an opportunity to learn tests while creating &lt;em&gt;Requests and Responses&lt;/em&gt; objects. Inside the PHP environment, you are probably using a 3rd party library like &lt;code&gt;PHPUnit&lt;/code&gt; or &lt;code&gt;Pest&lt;/code&gt;. Right? Inside the Go environment, this is &lt;strong&gt;EASY&lt;/strong&gt;! All you need to do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create a file inside a package:&lt;/strong&gt; In &lt;code&gt;person.go&lt;/code&gt; you will write the functions you want to test;&lt;/li&gt;
&lt;li&gt;Create a test file for your package :** create a file called &lt;code&gt;person_test.go&lt;/code&gt; and start writing your own tests!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's say we have &lt;code&gt;requests.go&lt;/code&gt; and &lt;code&gt;requests_test.go&lt;/code&gt; in our package folder, where &lt;code&gt;requests.go&lt;/code&gt; is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;  

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;  
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;VerbType&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;VerbGet&lt;/span&gt;  &lt;span class="n"&gt;VerbType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GET"&lt;/span&gt;  
    &lt;span class="n"&gt;VerbPost&lt;/span&gt; &lt;span class="n"&gt;VerbType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;  
&lt;span class="p"&gt;)&lt;/span&gt;  

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;Verb&lt;/span&gt;    &lt;span class="n"&gt;VerbType&lt;/span&gt;  
    &lt;span class="n"&gt;Version&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;Path&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;Headers&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;Params&lt;/span&gt;  &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;  
    &lt;span class="n"&gt;Body&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="n"&gt;payloadSlices&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  

    &lt;span class="n"&gt;verb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;extractRequestLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payloadSlices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;extractHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payloadSlices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payloadSlices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;payloadSlices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payloadSlices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;Verb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;VerbType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
       &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
       &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
       &lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
       &lt;span class="n"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;  
       &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;extractHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawHeaders&lt;/span&gt; &lt;span class="p"&gt;[][]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headerBytes&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;rawHeaders&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
       &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerBytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
       &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SplitN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;": "&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

       &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="kt"&gt;string&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="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c"&gt;// Accept (?)  &lt;/span&gt;
       &lt;span class="n"&gt;headers&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;value&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;headers&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;extractRequestLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestLine&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="n"&gt;splitRequestLine&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  
    &lt;span class="n"&gt;verb&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splitRequestLine&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splitRequestLine&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
    &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;splitRequestLine&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;verb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.1 Tests: Basic Testing
&lt;/h3&gt;

&lt;p&gt;A test in Go is considered &lt;code&gt;PASSED (green)&lt;/code&gt; if &lt;code&gt;(t *Testing.T).Errorf()&lt;/code&gt; is not called within your test function. It also follows the same concept of encapsulation introduced earlier: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test Functions&lt;/strong&gt; starting with &lt;strong&gt;uppercase are identified&lt;/strong&gt; by the Test Runner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Functions&lt;/strong&gt; starting with &lt;strong&gt;lowercase are ignored&lt;/strong&gt; (usually helper functions)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"reflect"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestNewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Prepare&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /index.html HTTP/1.1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Host: localhost:4221&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;User-Agent: curl/7.64.1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Accept: */*&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Act&lt;/span&gt;
    &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c"&gt;// Assert &lt;/span&gt;
    &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Verb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;VerbGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"HTTP/1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"/index.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeepEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FAILED! NewRequest() = %v, want %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do your own helper functions to test. Just make sure to not trespass the module domain on these tests!&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Tests: Jetbrains Boilerplate
&lt;/h3&gt;

&lt;p&gt;I've been using &lt;strong&gt;Goland&lt;/strong&gt; since day one, so most things have been easier for me. So every time I start a new test, I get this boilerplate with a Unity test structure that runs in parallel (goroutines) by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"reflect"&lt;/span&gt;
    &lt;span class="s"&gt;"testing"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestNewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;
        &lt;span class="n"&gt;want&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;
    &lt;span class="p"&gt;}{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Base Request Argless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET /index.html HTTP/1.1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Host: localhost:4221&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;User-Agent: curl/7.64.1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Accept: */*&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Verb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;VerbGet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"HTTP/1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"/index.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;reflect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeepEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NewRequest() = %v, want %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;want&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.3 Tests: Running Tests
&lt;/h3&gt;

&lt;p&gt;Ok, now we know &lt;strong&gt;how easy&lt;/strong&gt; it is to &lt;strong&gt;write tests&lt;/strong&gt; in Go, but how about &lt;strong&gt;running&lt;/strong&gt; them? &lt;strong&gt;Simple task&lt;/strong&gt;! All you need to do is navigate to the package folder and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/go_fodase&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;requests
&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;span class="c"&gt;# requests.go request_test.go&lt;/span&gt;
go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="c"&gt;# Run all tests inside the package in all files with suffix "_go"&lt;/span&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="c"&gt;# PASS&lt;/span&gt;
&lt;span class="c"&gt;# ok      github.com/danielhe4rt/go_fodase/requests/request      0.001s&lt;/span&gt;

go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;TestNewRequest &lt;span class="c"&gt;# Filter an specific test&lt;/span&gt;
&lt;span class="c"&gt;# PASS&lt;/span&gt;
&lt;span class="c"&gt;# ok      github.com/danielhe4rt/go_fodase/requests/request      0.001s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please write down some tests for your stuff. It's not that hard if you decouple what's needed :p &lt;/p&gt;

&lt;h2&gt;
  
  
  6. Beware Cyclic Imports
&lt;/h2&gt;

&lt;p&gt;During my last few years of development, I've always tried to modularise all my projects in a way that suits my needs, without getting stuck on &lt;strong&gt;"Clean Arch" or "Domain Driven Design"&lt;/strong&gt; stuff. However, in my first attempts at splitting my packages, I got the &lt;strong&gt;"Cyclic Import"&lt;/strong&gt; error and thought to myself: HOW LONG SINCE I'VE SEEN SOMETHING LIKE THAT?&lt;/p&gt;

&lt;p&gt;During my 2 years in PHP, I had the same problem with &lt;code&gt;import hell&lt;/code&gt;, where you couldn't &lt;strong&gt;not import the same file TWICE&lt;/strong&gt; in a particular flow. This was before I met the &lt;a href="https://www.php-fig.org/psr/psr-4/" rel="noopener noreferrer"&gt;PSR-4 (Autoloading)&lt;/a&gt; (which changed my PHP days forever!!) and now, years ago, I'm struggling with this in Go.&lt;/p&gt;

&lt;p&gt;Let's consider a scenario of cyclic imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ------------------&lt;/span&gt;
&lt;span class="c1"&gt;// A.php&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="s1"&gt;'B.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello from A&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ------------------&lt;/span&gt;
&lt;span class="c1"&gt;// B.php&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="s1"&gt;'A.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&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;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Hello from B&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ------------------&lt;/span&gt;
&lt;span class="c1"&gt;// index.php&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="s1"&gt;'A.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Fatal error: Uncaught Error: Maximum function nesting level of '256' reached...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you try to compile something that flags &lt;code&gt;Cyclic Imports&lt;/code&gt; in Go, you will receive an error like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import cycle not allowed
package path/to/packageA
    imports path/to/packageB
    imports path/to/packageA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in this moment, you have to start breaking down your dependencies/packages in order to avoid it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt;: don't import the same package in a place that will be loaded many times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  7. Defer this, defer that... But, what is a Defer?
&lt;/h2&gt;

&lt;p&gt;I didn't look it up, but it was the first time I'd seen the reserved word &lt;code&gt;defer&lt;/code&gt; in a programming language. And since it was not part of the &lt;strong&gt;"generic reserved words"&lt;/strong&gt;, I ignored it for a whole week!&lt;/p&gt;

&lt;p&gt;Then one of my work mates, &lt;a href="https://github.com/codelieutenant" rel="noopener noreferrer"&gt;Dusan&lt;/a&gt;, gave me a memory management lesson in Go after seeing me struggle with the language for a couple of hours. (Yes, this is a shout-out :p)&lt;/p&gt;

&lt;p&gt;The thing is: whenever you open a buffer/connection to something, you SHOULD CLOSE IT! I remember when I was working with MapleStory servers (Java) in 2014, the most common problem was &lt;strong&gt;memory leaks&lt;/strong&gt;, simply because the developers didn't close the connections to the DB. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is OK to FORGET! But it's not OK to pass in the Code Review LOL&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's an example in Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.Connection&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.DriverManager&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.ResultSet&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.Statement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.sql.SQLException&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UnclosedConnectionExample&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Database credentials&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jdbc:mysql://localhost:3306/mydatabase"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Establishing the connection&lt;/span&gt;
                &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Database connected successfully."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Creating a statement&lt;/span&gt;
                &lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createStatement&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

                &lt;span class="c1"&gt;// Executing a query&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT id, name, email FROM users"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Processing the result set&lt;/span&gt;
                &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ID: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", Name: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", Email: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;

                &lt;span class="c1"&gt;// Intentionally not closing the resources&lt;/span&gt;
                &lt;span class="c1"&gt;// rs.close() // &amp;lt;-------------------&lt;/span&gt;
                &lt;span class="c1"&gt;// This leads to resource leaks&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SQLException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// rs.close() // &amp;lt;-------------------&lt;/span&gt;
                &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While coding Golang, they give this &lt;code&gt;defer&lt;/code&gt; attribute for you to remember to close your stuff right after opening it. &lt;/p&gt;

&lt;p&gt;Defer stands for "Deference" which is a way to &lt;strong&gt;"Clean"&lt;/strong&gt; your resources after the execution of that specific portion of code ends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gocql/gocql"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gocql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localhost:9042"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Connection Refused!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;  
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// After the function ends, the method will be called&lt;/span&gt;

    &lt;span class="c"&gt;// Migrate stuff  &lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Migrating Tables..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// ... rest of your code&lt;/span&gt;

    &lt;span class="c"&gt;// After the last line of code, the function `session.Close()` will run without you trigger it. &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also have many &lt;code&gt;defer&lt;/code&gt;'s within a function and the &lt;strong&gt;DEFER ORDER&lt;/strong&gt; matters! If you defer &lt;strong&gt;database2&lt;/strong&gt; and then defer &lt;strong&gt;database1&lt;/strong&gt;, both processes will be cleaned in the same order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gocql/gocql"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gocql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localhost:9042"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  

    &lt;span class="n"&gt;loggingSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="n"&gt;appSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;appSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;loggingSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// ... rest of your code&lt;/span&gt;
    &lt;span class="c"&gt;// Defer Order&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
    &lt;span class="c"&gt;// appSession.close() 1st&lt;/span&gt;
    &lt;span class="c"&gt;// loggingSession.close() 2nd&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a really simple way to &lt;del&gt;not fuck up&lt;/del&gt; prevent your project from having a memory leak. Please remember to use it whenever you stream anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Error Management for Noobs
&lt;/h2&gt;

&lt;p&gt;Error handling at first will be something like: check if the function you're using returns an &lt;code&gt;error&lt;/code&gt; type and validate it EVERY &lt;del&gt;FUCKING&lt;/del&gt; TIME! Here's an example of what I'm talking about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gocql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localhost:9042"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="n"&gt;appSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  

&lt;span class="c"&gt;// NIL STUFF&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// do something&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Well, something went wrong."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;appSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;// Keep your flow. &lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be honest, I HATE this syntax. However, it's part of the language and will be something you'll come across during your days of coding. &lt;/p&gt;

&lt;p&gt;Functions with errors can return &lt;code&gt;error&lt;/code&gt; or &lt;code&gt;(T, error)&lt;/code&gt;, and fortunately Go will not let you forget that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SumNumbers&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="n"&gt;b&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The result is negative."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Using it&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;always&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;possible&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spam&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; 
&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SumNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Ends the app or handle in the way you want.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spam your code with &lt;code&gt;err != nil&lt;/code&gt; and you will be fine, I promise! :D&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Conclusion feat: Low Latency Coding Challenge
&lt;/h2&gt;

&lt;p&gt;Aside from all the stress and hours spent trying to understand the environment, it was a cool challenge to learn a new language together with my &lt;a href="https://twitch.tv/danielhe4rt" rel="noopener noreferrer"&gt;Twitch viewers&lt;/a&gt;. Many of them have been asking me for a long time to check it out and here we are.&lt;/p&gt;

&lt;p&gt;All of these points reflect my personal development experience with the language, and the goal was to share things I've gone through during these 2 weeks of studying it.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.1 Bonus: Coding Challenge
&lt;/h3&gt;

&lt;p&gt;Recently I was challenged by my teammate to complete a ScyllaDB challenge and it taught me a lot about parallelism, pools and rate limiting. This is the kind of challenge that many companies face to make their products perform better!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The goal of the challenge is to create a small Go command line application that inserts some random data into ScyllaDB while rate limiting the number of requests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can find the repository challenge here: &lt;a href="https://github.com/DanielHe4rt/throttiling-requests-scylladb-go-test" rel="noopener noreferrer"&gt;github.com/basementdevs/throttling-requests-scylla-test&lt;/a&gt;. We're also hiring! You can find the open positions in our &lt;a href="https://www.scylladb.com/company/careers/" rel="noopener noreferrer"&gt;careers section&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thank you for reading! I hope this article has provided valuable insights into learning Golang. Feel free to share your thoughts or experiences.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>scylladb</category>
      <category>go</category>
      <category>tutorial</category>
      <category>todayisearched</category>
    </item>
    <item>
      <title>Database 101: SSL/TLS for beginners</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Fri, 04 Oct 2024 15:33:01 +0000</pubDate>
      <link>https://forem.com/scylladb/database-101-ssltls-for-beginners-4lmn</link>
      <guid>https://forem.com/scylladb/database-101-ssltls-for-beginners-4lmn</guid>
      <description>&lt;p&gt;Once again, I'm bringing some knowledge from my day-to-day work as a Developer Advocate at &lt;a href="https://scylladb.com" rel="noopener noreferrer"&gt;ScyllaDB&lt;/a&gt;, and this time I'm going to teach you about secure and encrypted connections ! It's a topic that can cause a lot of anxiety for newbies, but I'm going to make it easier for you.&lt;/p&gt;

&lt;p&gt;If you're just getting started with databases in general or databases in particular, you might want to start by reading my first article, &lt;a href="https://dev.to/danielhe4rt/database-101-why-so-interesting-1344"&gt;Database 101: Data Consistency for Beginners&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This article captures my own exploration of how many database paradigms exist as I look far beyond my previous experience with just SQL and MySQL. I'm keeping track of my studies in this &lt;strong&gt;Database 101&lt;/strong&gt; series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Prologue&lt;/li&gt;
&lt;li&gt;2. What is SSL and TLS?&lt;/li&gt;
&lt;li&gt;3. OpenSSL for Noobs&lt;/li&gt;
&lt;li&gt;
4. Database Authentication

&lt;ul&gt;
&lt;li&gt;4.1 No Authentication&lt;/li&gt;
&lt;li&gt;4.2 Username/Password Authentication&lt;/li&gt;
&lt;li&gt;4.3 Creating Users and Roles&lt;/li&gt;
&lt;li&gt;
4.4 Certificated / Role Certificated Authentication

&lt;ul&gt;
&lt;li&gt;4.4.1 Change the Authentication Type&lt;/li&gt;
&lt;li&gt;4.4.2 Enable the Encryption Port&lt;/li&gt;
&lt;li&gt;4.4.3 Enable the Client Encryption Port&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;5. Testing Encrypted Connections&lt;/li&gt;

&lt;li&gt;6. Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prologue
&lt;/h2&gt;

&lt;p&gt;Working on a NoSQL database is challenging in the sense that I have to learn stuff that I'd NEVER touch or study as a regular web developer. I mean, mostly you build a CRUD application, try your best not to screw up the database indexes (right guys ??????) and paint a few buttons.&lt;/p&gt;

&lt;p&gt;But if you've been following my Database 101 journey, you probably know that I came to Scylla knowing NOTHING about databases except what MySQL was and how to build things with Laravel, and now I'm into it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building Highly Scalable Applications with ScyllaDB&lt;/li&gt;
&lt;li&gt;Still learning Rust - 1 year and 6 months &lt;strong&gt;(and I feel like I know shit about it)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Started learning ShellScript, Go, Python, JavaScript, and anything that has a ScyllaDB driver&lt;/li&gt;
&lt;li&gt;Learned the basics of observability using Grafana/Prometheus&lt;/li&gt;
&lt;li&gt;and my new friend &lt;strong&gt;Transport Layer Security&lt;/strong&gt; (a.k.a. &lt;strong&gt;TLS&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're setting up your own servers, you've probably already used &lt;a href="https://certbot.com" rel="noopener noreferrer"&gt;certbot&lt;/a&gt; to install certificates to run HTTPS smoothly, and that's what I've been doing for the last 6~7 years. To be really honest, knowing how to use a tool is what we &lt;em&gt;developers&lt;/em&gt; do. &lt;/p&gt;

&lt;p&gt;It even seems like an omen, but I'm working on a browser extension whose backend is written in Rust, and I didn't manage to use &lt;code&gt;certbot&lt;/code&gt; there, so I had to create my certificate using weird commands and add a weird &lt;code&gt;openssl&lt;/code&gt; crate to &lt;a href="https://github.com/basementdevs/tbp-consumer-api/blob/e130e279b6b53d34e3ba9270f3d4c211a815582b/src/main.rs#L31" rel="noopener noreferrer"&gt;my project&lt;/a&gt; and trust that it would work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;certs_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BufReader&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cert_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;key_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BufReader&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;File&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// load TLS certs and key to create a self-signed temporary cert for testing:&lt;/span&gt;
&lt;span class="c1"&gt;// `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'`&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tls_certs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;rustls_pemfile&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;certs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;certs_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="py"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&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;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tls_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;rustls_pemfile&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;pkcs8_private_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;key_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few hours of trying/catching, I finally managed to deploy the API with the certificate, but I didn't learn anything about it. THEN, a few days later, my boss asked me to extend the &lt;a href="https://opensource.docs.scylladb.com/branch-6.0/operating-scylla/security/index.html" rel="noopener noreferrer"&gt;ScyllaDB Security Pages&lt;/a&gt; and learn how &lt;strong&gt;Certificated Based Connection&lt;/strong&gt; works, since I'd never used it. &lt;/p&gt;

&lt;p&gt;I spent 10 hours on it and managed to get it to work, but mostly it wasn't about the documentation, it was about &lt;strong&gt;my lack of knowledge&lt;/strong&gt; in this area, which is no longer a problem and I will teach you everything I've learned so far!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What is SSL and TLS?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: this is that boring section which you can skip if you want. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;SSL (Secure Sockets Layer) was introduced in 1995 by Netscape to provide privacy, authentication, and data integrity for internet communications, primarily in browsers. TLS (Transport Layer Security), which succeeded SSL, is now the standard security protocol used across the internet for applications like email, messaging, and VoIP.&lt;/p&gt;

&lt;p&gt;Without SSL/TLS, data transmitted between a client and a server is unencrypted and vulnerable to interception and misuse, making it an easy target for phishing and other attacks. SSL/TLS ensures that a secure "handshake" occurs before data transmission, meaning that all data is encrypted for that specific session.&lt;/p&gt;

&lt;p&gt;However, even though SSL/TLS provides encryption, it doesn’t guarantee that the server itself is fully trustworthy or secure. SSL, being deprecated since 1996 due to its vulnerabilities, is still often referenced alongside TLS by developers as "SSL/TLS" because of its historical significance.&lt;/p&gt;

&lt;p&gt;With this understanding of SSL/TLS, let’s now dive into the tools that help manage secure connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. OpenSSL for Noobs
&lt;/h2&gt;

&lt;p&gt;There are many data encryption toolkits available today, but we're going to talk about a very specific one: the &lt;a href="https://openssl-library.org/" rel="noopener noreferrer"&gt;openssl-library.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This library, which had its first release in 1998, is attached to &lt;em&gt;every single tutorial&lt;/em&gt; on data encryption, and is used by many other tools around the open/closed source environment - such as Let's Encrypt and Certbot - and the one we're going to use here. &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%2Fb017wsv0r8ld8l10rjb1.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%2Fb017wsv0r8ld8l10rjb1.png" alt="OpenSSL Manual" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The purpose of this tool is to create keychains and credentials to authorize someone to do whatever you want. &lt;/p&gt;

&lt;p&gt;Imagine you work in a commercial building where you have to show your badge to security to get in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your company creates a &lt;strong&gt;"master key"&lt;/strong&gt; and generates a certificate for it. &lt;/li&gt;
&lt;li&gt;You also generate a &lt;strong&gt;key and certificate&lt;/strong&gt; for the security guard and give them to him along with a list of all the employee's certificates.&lt;/li&gt;
&lt;li&gt;The guard has a &lt;strong&gt;truststore keychain&lt;/strong&gt; with all sorts of tags on it.&lt;/li&gt;
&lt;li&gt;When you arrive at the entrance, he will check that your tag has the same root certificate as his to decide whether you can pass or not.&lt;/li&gt;
&lt;/ul&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%2Fhvdj4670oqksjerytc0m.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%2Fhvdj4670oqksjerytc0m.png" alt="Encryption Purpose Diagram" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In matter of commands, we did something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Creating the root/master key and certificate&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;
openssl genpkey &lt;span class="nt"&gt;-algorithm&lt;/span&gt; RSA &lt;span class="nt"&gt;-out&lt;/span&gt; root_key.pem &lt;span class="nt"&gt;-pkeyopt&lt;/span&gt; rsa_keygen_bits:2048 &lt;span class="c"&gt;# Generate the root key&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; root_key.pem &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="nt"&gt;-out&lt;/span&gt; root_cert.pem &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=administrator"&lt;/span&gt; &lt;span class="c"&gt;# Generate the root certificate&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;

&lt;span class="c"&gt;# Creating the Employee Key and Certificate&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;
openssl genpkey &lt;span class="nt"&gt;-algorithm&lt;/span&gt; RSA &lt;span class="nt"&gt;-out&lt;/span&gt; employee_key.pem &lt;span class="nt"&gt;-pkeyopt&lt;/span&gt; rsa_keygen_bits:2048 &lt;span class="c"&gt;# Generate the employee base key&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; employee_key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; employee.csr &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=employee"&lt;/span&gt; &lt;span class="c"&gt;# Generate the employee CSR&lt;/span&gt;
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; employee.csr &lt;span class="nt"&gt;-CA&lt;/span&gt; root_cert.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; root_key.pem &lt;span class="nt"&gt;-CAcreateserial&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; employee_cert.pem &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="c"&gt;# Sign and generate the employee certificate with the root/master key and certificate&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;root_cert.pem employee_cert.pem &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; employee_truststore.pem &lt;span class="c"&gt;# Create a truststore (tag) to be used together with the key.&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;

&lt;span class="c"&gt;# Creating the Security (server) Key and Certificate&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;
openssl genpkey &lt;span class="nt"&gt;-algorithm&lt;/span&gt; RSA &lt;span class="nt"&gt;-out&lt;/span&gt; security_key.pem &lt;span class="nt"&gt;-pkeyopt&lt;/span&gt; rsa_keygen_bits:2048 &lt;span class="c"&gt;# Generate the security key&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; security_key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; security.csr &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=server"&lt;/span&gt; &lt;span class="c"&gt;# Generate the security CSR&lt;/span&gt;
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; security.csr &lt;span class="nt"&gt;-CA&lt;/span&gt; root_cert.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; root_key.pem &lt;span class="nt"&gt;-CAcreateserial&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; security_cert.pem &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="c"&gt;# Sign and generate the security certificate with the root/master key and certificate&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;root_cert.pem security_cert.pem &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; security_truststore.pem &lt;span class="c"&gt;# Create a truststore (tag) to be used together with the key.&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;


&lt;span class="c"&gt;# Creating the Malicious Root and Client Key and Certificate&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;
openssl genpkey &lt;span class="nt"&gt;-algorithm&lt;/span&gt; RSA &lt;span class="nt"&gt;-out&lt;/span&gt; malicious_key.pem &lt;span class="nt"&gt;-pkeyopt&lt;/span&gt; rsa_keygen_bits:2048 &lt;span class="c"&gt;# Generate the malicious root key&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; malicious_key.pem &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="nt"&gt;-out&lt;/span&gt; malicious_cert.pem &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=fake-admin"&lt;/span&gt; &lt;span class="c"&gt;# Generate the malicious root certificate&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;root_cert.pem malicious_cert.pem &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; malicious_truststore.pem &lt;span class="c"&gt;# Combine root and malicious root certificates into a truststore&lt;/span&gt;
&lt;span class="c"&gt;# -----&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are too many commands, but basically this is what happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;root_key.pem&lt;/code&gt; and &lt;code&gt;root_cert.pem&lt;/code&gt; were generated.&lt;/li&gt;
&lt;li&gt;These keys and certificates were used to sign other keys and certificates for employees:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;security_key.pem&lt;/code&gt; was signed by &lt;code&gt;root_key.pem&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;employee_key.pem&lt;/code&gt; was signed by &lt;code&gt;root_key.pem&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;server_key.pem&lt;/code&gt; has been signed by &lt;code&gt;root_key.pem&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;All these keys are in a file called &lt;code&gt;security_truststore.pem&lt;/code&gt;. &lt;/li&gt;

&lt;li&gt;Someone tried to create a &lt;strong&gt;fake key&lt;/strong&gt; called &lt;code&gt;malicious_key.pem&lt;/code&gt; using the &lt;code&gt;root_cert.pem&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now let's do some validation. Theoretically, only the keys in &lt;code&gt;security_truststore.pem&lt;/code&gt; should be allowed to join:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Validating the certificates with the truststores&lt;/span&gt;
&lt;span class="c"&gt;# ----- &lt;/span&gt;
openssl verify &lt;span class="nt"&gt;-CAfile&lt;/span&gt; security_truststore.pem employee_cert.pem &lt;span class="c"&gt;# Check if the certificate is valid&lt;/span&gt;
&lt;span class="c"&gt;# employee_cert.pem: OK&lt;/span&gt;

openssl verify &lt;span class="nt"&gt;-CAfile&lt;/span&gt; security_truststore.pem malicious_cert.pem &lt;span class="c"&gt;# Check if the certificate is valid&lt;/span&gt;
&lt;span class="c"&gt;# CN = fake-admin&lt;/span&gt;
&lt;span class="c"&gt;#  error 18 at 0 depth lookup: self-signed certificate&lt;/span&gt;
&lt;span class="c"&gt;#  error malicious_cert.pem: verification failed&lt;/span&gt;
&lt;span class="c"&gt;# ----- &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And as expected, since the malicious key is not signed by the root user, authentication fails and that person is kicked out. &lt;/p&gt;

&lt;p&gt;So now we know the basics of encryption. But where do you use it in the real world? Let me tell you more about my current task and then you will understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Database Authentication
&lt;/h2&gt;

&lt;p&gt;Say you're running any database (e.g. MySQL, Postgres, ScyllaDB, Redis, etc.) in Docker. When you spin up these instances in a containerized environment, you usually don't need a password unless you set one. In any case, we have a number of options when we talk about authentication in any part of the modern web, and the same is true when we're talking about databases.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Were going to use &lt;a href="https://scylladb.com" rel="noopener noreferrer"&gt;ScyllaDB&lt;/a&gt; in this example however this flow is pretty common in &lt;strong&gt;many databases&lt;/strong&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this step, we're going to learn about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No Authentication:&lt;/strong&gt; Literally no credentials required, just spin your instance and be happy;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Username/Password Authentication:&lt;/strong&gt; Some basic credentials are fine to keep people away from your data;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certified / Role Certified Authentication:&lt;/strong&gt; This is where the big companies like to play and you should learn that.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this brief introduction of encryption 101, we can get started with the content itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 No Authentication
&lt;/h3&gt;

&lt;p&gt;In Scylla, if you're running a node or cluster in the development environment (locally or using Docker), there is no password by default. Also, &lt;strong&gt;ScyllaDB uses the CQL protocol on port 9042&lt;/strong&gt; by default, which can be easily changed in the config files.&lt;/p&gt;

&lt;p&gt;Why am I telling you this port information? Because this information will be important later, trust me. &lt;/p&gt;

&lt;p&gt;You can spin up a Docker instance by running it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Running a ScyllaDB Node with Docker&lt;/span&gt;
docker  run &lt;span class="nt"&gt;--name&lt;/span&gt; some_scylla &lt;span class="nt"&gt;-p&lt;/span&gt; 9042:9042 &lt;span class="nt"&gt;-p&lt;/span&gt; 9142:9142 &lt;span class="nt"&gt;-d&lt;/span&gt; scylladb/scylla:6.1.2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overprovisioned&lt;/span&gt; 1 &lt;span class="nt"&gt;--smp&lt;/span&gt; 1 

&lt;span class="c"&gt;# Checking the node status -&amp;gt; Expect for UN (Up And Running)Cassandra&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla nodetool status
&lt;span class="c"&gt;# Datacenter: datacenter1&lt;/span&gt;
&lt;span class="c"&gt;# =======================&lt;/span&gt;
&lt;span class="c"&gt;# Status=Up/Down&lt;/span&gt;
&lt;span class="c"&gt;# |/ State=Normal/Leaving/Joining/Moving&lt;/span&gt;
&lt;span class="c"&gt;# -- Address   Load      Tokens Owns Host ID                              Rack &lt;/span&gt;
&lt;span class="c"&gt;# UN 10.10.5.2 509.46 KB 256    ?    9f597eb5-a77f-493f-9835-85dd1e571fcc rack1&lt;/span&gt;
&lt;span class="c"&gt;# --&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you can login at &lt;strong&gt;cqlsh (CQL Shell)&lt;/strong&gt; by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla cqlsh
&lt;span class="c"&gt;# Connected to  at 10.10.5.5:9042&lt;/span&gt;
&lt;span class="c"&gt;# [cqlsh 6.0.18 | Scylla 6.0.1-0.20240612.bc89aac9d017 | CQL spec 3.3.1 | Native protocol v4]&lt;/span&gt;
&lt;span class="c"&gt;# Use HELP for help.&lt;/span&gt;
&lt;span class="c"&gt;# cqlsh&amp;gt; select address, port, client_type, username from system.clients;&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;#  address   | port  | client_type | username&lt;/span&gt;
&lt;span class="c"&gt;# -----------+-------+-------------+-----------&lt;/span&gt;
&lt;span class="c"&gt;#  10.10.5.5 | 50854 |         cql | anonymous&lt;/span&gt;
&lt;span class="c"&gt;#  10.10.5.5 | 50868 |         cql | anonymous&lt;/span&gt;
&lt;span class="c"&gt;# -----------+-------+-------------+-----------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeah, we're connected as &lt;strong&gt;anonymous users&lt;/strong&gt;! Perfect for developing new stuff and &lt;strong&gt;testing locally&lt;/strong&gt;. But then you decide to deploy the same configuration into production... &lt;/p&gt;

&lt;p&gt;And OF COURSE that, in less than an hour you'll be owned by some random database crawler LOL.&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%2Fm58lj3s8lsd3285nu9jc.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%2Fm58lj3s8lsd3285nu9jc.png" alt="Owned PostgreSQL" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can read more about &lt;a href="https://www.helpnetsecurity.com/2024/01/18/postgresql-mysql-ransomware-bot/" rel="noopener noreferrer"&gt;this ransomware&lt;/a&gt; if you want. Anyway, let's add some base credentials and configure it properly in the next step.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Seriously, don't open your database to the Internet with the default configurations or without binding a unique IP address to access it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4.2 Username/Password Authentication
&lt;/h3&gt;

&lt;p&gt;While running any of these other databases, you have the ability to switch authentication types by changing a bunch of configuration files. At &lt;strong&gt;ScyllaDB&lt;/strong&gt;, we're really proud of how &lt;strong&gt;modular and easy&lt;/strong&gt; the configuration is.&lt;/p&gt;

&lt;p&gt;If you look at &lt;code&gt;/etc/scylla/scylla.yaml&lt;/code&gt; in your docker (you can get a better look at the repository by &lt;a href="https://github.com/scylladb/scylladb/blob/master/conf/scylla.yaml#L247" rel="noopener noreferrer"&gt;clicking here (file: scylla.yaml#247)&lt;/a&gt;, you will find these configuration flags:&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="c1"&gt;# file: /etc/scylla/scylla.yaml&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="c1"&gt;# Authentication backend, identifying users&lt;/span&gt;
&lt;span class="c1"&gt;# Out of the box, Scylla provides org.apache.cassandra.auth.{AllowAllAuthenticator,&lt;/span&gt;
&lt;span class="c1"&gt;# PasswordAuthenticator}.&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# - AllowAllAuthenticator performs no checks - set it to disable authentication.&lt;/span&gt;
&lt;span class="c1"&gt;# - PasswordAuthenticator relies on username/password pairs to authenticate&lt;/span&gt;
&lt;span class="c1"&gt;#   users. It keeps usernames and hashed passwords in system_auth.credentials table.&lt;/span&gt;
&lt;span class="c1"&gt;#   Please increase system_auth keyspace replication factor if you use this authenticator.&lt;/span&gt;
&lt;span class="c1"&gt;# - com.scylladb.auth.TransitionalAuthenticator requires username/password pair&lt;/span&gt;
&lt;span class="c1"&gt;#   to authenticate in the same manner as PasswordAuthenticator, but improper credentials&lt;/span&gt;
&lt;span class="c1"&gt;#   result in being logged in as an anonymous user. Use for upgrading clusters' auth.&lt;/span&gt;
&lt;span class="c1"&gt;# authenticator: AllowAllAuthenticator&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default is the &lt;code&gt;AllowAllAuthenticator&lt;/code&gt; which allows anonymous connection with superpowers. Now, we'll uncomment the &lt;code&gt;# authenticator:&lt;/code&gt; line and replace with &lt;code&gt;PasswordAuthenticator&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;# file: /etc/scylla/scylla.yaml
# ...
&lt;span class="gd"&gt;-#authenticator: AllowAllAuthenticator  # line ~247
&lt;/span&gt;&lt;span class="gi"&gt;+authenticator: PasswordAuthenticator
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay! Now we just need to tell our Scylla node that we have made this change. Since this is a "critical" change to our system environment, we'll need to &lt;code&gt;drain&lt;/code&gt; and then restart the node. Here's a step-by-step guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before Editing&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla nodetool drain &lt;span class="c"&gt;# Stop gossiping and preparing to shut down&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla supervisorctl stop scylla &lt;span class="c"&gt;# Stop ScyllaDB&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/scylla/scylla.yaml | &lt;span class="nb"&gt;grep &lt;/span&gt;authenticator: &lt;span class="c"&gt;# Check the current flag&lt;/span&gt;

&lt;span class="c"&gt;# Edit /etc/scylla/scylla.yaml ...&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/# authenticator:.*/authenticator: PasswordAuthenticator/'&lt;/span&gt; /etc/scylla/scylla.yaml

&lt;span class="c"&gt;# After Edit&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla &lt;span class="nb"&gt;cat&lt;/span&gt; /etc/scylla/scylla.yaml | &lt;span class="nb"&gt;grep &lt;/span&gt;authenticator: &lt;span class="c"&gt;# Check if the update is there&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla supervisorctl start scylla &lt;span class="c"&gt;# Run ScyllaDB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that we're finally able to run &lt;code&gt;cqlsh&lt;/code&gt; and receives a huge "YOU NEED CREDENTIALS, BITCH":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla cqlsh
Connection error: &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Unable to connect to any servers'&lt;/span&gt;, &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'10.10.5.5:9042'&lt;/span&gt;: AuthenticationFailed&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Remote end requires authentication'&lt;/span&gt;&lt;span class="o"&gt;)})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and by default, at ScyllaDB, we can login using the username/password "cassandra" (superuser):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla cqlsh &lt;span class="nt"&gt;-u&lt;/span&gt; cassandra &lt;span class="nt"&gt;-p&lt;/span&gt; cassandra
&lt;span class="c"&gt;# Connected to  at 10.10.5.5:9042&lt;/span&gt;
&lt;span class="c"&gt;# [cqlsh 6.0.18 | Scylla 6.0.1-0.20240612.bc89aac9d017 | CQL spec 3.3.1 | Native protocol v4]&lt;/span&gt;
&lt;span class="c"&gt;# Use HELP for help.&lt;/span&gt;
&lt;span class="c"&gt;# cassandra@cqlsh&amp;gt; select address, port, client_type, username from system.clients; &lt;/span&gt;

&lt;span class="c"&gt;#  address   | port  | client_type | username&lt;/span&gt;
&lt;span class="c"&gt;# -----------+-------+-------------+-----------&lt;/span&gt;
&lt;span class="c"&gt;#  10.10.5.5 | 56998 |         cql | cassandra&lt;/span&gt;
&lt;span class="c"&gt;#  10.10.5.5 | 57014 |         cql | cassandra&lt;/span&gt;
&lt;span class="c"&gt;# -----------+-------+-------------+-----------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... with that, we know the basics of how to configure authentication in ScyllaDB, and if you want to know why the user/password is "cassandra", you can read my &lt;a href="https://dev.to/danielhe4rt/database-101-why-so-interesting-1344"&gt;first article&lt;/a&gt; from this series. Also, be sure to change your default credentials before deploying it. &lt;/p&gt;

&lt;p&gt;The CQL protocol runs on port 9042 by default and is well known. In the same way that you can get owned by just letting your database run without authentication, you can &lt;strong&gt;get owned&lt;/strong&gt; by letting the default credentials there.&lt;/p&gt;

&lt;p&gt;At the moment, all connections still &lt;code&gt;unencrypted&lt;/code&gt; but at least we have a minimum security, but don't worry! We're about fix the encryption soon!  Before that, let's create some users/roles inside our database.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Creating Users and Roles
&lt;/h3&gt;

&lt;p&gt;Before creating new users for this database, we need to understand how it works. At Scylla we use &lt;code&gt;Role Based Authentication&lt;/code&gt; every day. So every user is placed in &lt;code&gt;system.roles&lt;/code&gt; as a role. &lt;/p&gt;

&lt;p&gt;This is not a problem because you can set a &lt;code&gt;PASSWORD&lt;/code&gt; to a role. It looks weird, but I'll show you how it works. Check it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scylladb@cqlsh&amp;gt; desc system.roles;

CREATE TABLE system.roles (
    role text,
    can_login boolean,
    is_superuser boolean,
    member_of set&amp;lt;text&amp;gt;,
    salted_hash text,
    PRIMARY KEY (role)
);

scylladb@cqlsh&amp;gt; select * from system.roles;

 role        | can_login | is_superuser |     member_of | salted_hash
-------------+-----------+--------------+---------------+--------------------
 scylladb    |      True |         True |          null | $6$rAJ6FflUo8Chf...
 employee    |     False |        False |          null | null
 danielhe4rt |      True |        False |  {'employee'} | $6$AF4F6CflAA8Cw...
-------------+-----------+--------------+---------------+--------------------


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output gives us some information about the authentication itself, such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A role becomes an authenticatable when the &lt;code&gt;can_login&lt;/code&gt; flag is set to &lt;code&gt;true&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;A role must/can have a password after it becomes an authenticatable;&lt;/li&gt;
&lt;li&gt;A role can belong to &lt;code&gt;another role&lt;/code&gt;, which will inherit all privileges from it.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This is just an environment created to give you an example of how the modeling and features work. Be sure to read the documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a matter of &lt;strong&gt;DCL (Data Control Language)&lt;/strong&gt; and &lt;strong&gt;DML (Data Manipulation Language)&lt;/strong&gt;, we'll do basic commands like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Create our user/roles&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;developer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;danielhe4rt&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'some_cool_password'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Grant roles to our users&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="n"&gt;developer&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;danielhe4rt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... which we will be running at our ScyllaDB Docker Instance following the keys created in the beginning of the article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some-scylla cqlsh &lt;span class="nt"&gt;-u&lt;/span&gt; cassandra &lt;span class="nt"&gt;-p&lt;/span&gt; cassandra &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"CREATE ROLE IF NOT EXISTS 'employee' WITH LOGIN = true;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some-scylla cqlsh &lt;span class="nt"&gt;-u&lt;/span&gt; cassandra &lt;span class="nt"&gt;-p&lt;/span&gt; cassandra &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"CREATE ROLE IF NOT EXISTS 'server' WITH LOGIN = true;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: You can only create new roles/users using an authenticated account&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4.4 Certificated / Role Certificated Authentication
&lt;/h3&gt;

&lt;p&gt;At the beginning of this tutorial we introduced the topic by talking about a story of someone with valid keys to enter a building and now the goal is to understand what is different from a regular authentication. As I said, without TLS/SSL, your data is in transit without any encryption, and that's BAD depending on the content you're sending/receiving.&lt;/p&gt;

&lt;p&gt;Using a certificate means that before you send your data out, we have guarantees that if someone intercepts the data, it won't be a problem if they don't have the key to decrypt it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, ScyllaDB listens to the CQL protocol on port 9042, which can be configured using the &lt;code&gt;native_transport_port&lt;/code&gt; configuration option.&lt;/li&gt;
&lt;li&gt;Scylla also supports the CQL protocol via TLS/SSL encryption, which is disabled by default and can be enabled using the &lt;code&gt;native_transport_port_ssl&lt;/code&gt; configuration option.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The traditional choice of port for secure connections is 9142, but if &lt;code&gt;client_encryption_options&lt;/code&gt; is specified and &lt;code&gt;native_transport_port_ssl&lt;/code&gt; is not, then &lt;code&gt;native_transport_port&lt;/code&gt; will only handle encrypted connections. The same thing happens if &lt;code&gt;native_transport_port&lt;/code&gt; and &lt;code&gt;native_transport_port_ssl&lt;/code&gt; are set to the same value.&lt;/p&gt;

&lt;p&gt;I know, it seems a bit crazy with all these flags and options, but I'll try to make it simpler. Check out the rules that govern port assignment/encryption, which are summarized in the table below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;np  := native_transport_port is set
nps := native_transport_port_ssl is set
ceo := client_encryption_options are enabled
eq  := native_transport_port_ssl == native_transport_port

+-----+-----+-----+-----+
|  np | nps | ceo |  eq |
+-----+-----+-----+-----+
|  0  |  0  |  0  |  *  |   =&amp;gt;   listen on native_transport_port, unencrypted
|  0  |  0  |  1  |  *  |   =&amp;gt;   listen on native_transport_port, encrypted
|  0  |  1  |  0  |  *  |   =&amp;gt;   don't listen
|  0  |  1  |  1  |  *  |   =&amp;gt;   listen on native_transport_port_ssl, encrypted
|  1  |  0  |  0  |  *  |   =&amp;gt;   listen on native_transport_port, unencrypted
|  1  |  0  |  1  |  *  |   =&amp;gt;   listen on native_transport_port, encrypted
|  1  |  1  |  0  |  *  |   =&amp;gt;   listen on native_transport_port, unencrypted
|  1  |  1  |  1  |  0  |   =&amp;gt;   listen on native_transport_port, unencrypted + native_transport_port_ssl, encrypted
|  1  |  1  |  1  |  1  |   =&amp;gt;   listen on native_transport_port(_ssl - same thing), encrypted
+-----+-----+-----+-----+

// More at: https://github.com/scylladb/scylladb/blob/master/docs/dev/protocols.md#cql-client-protocol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells us that if we want to enable encryption, we need to update a few more things in &lt;code&gt;scylla.yaml&lt;/code&gt;. Instead of using the &lt;code&gt;PasswordAuthenticator&lt;/code&gt;, we'll switch to the &lt;code&gt;com.scylladb.auth.CertificateAuthenticator&lt;/code&gt; feature.&lt;/p&gt;

&lt;p&gt;Before we change anything, let's drain and stop our cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla nodetool drain &lt;span class="c"&gt;# Stop gossiping and preparing to shut down&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla supervisorctl stop scylla &lt;span class="c"&gt;# Stop ScyllaDB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous step we created some roles with LOGIN enabled. And we added these "roles" to our OpenSSL commands at the top with a &lt;strong&gt;CN=server/blabla&lt;/strong&gt;, right? Now it's time to make it useful and not use credentials anymore.&lt;/p&gt;

&lt;p&gt;Private Keys + Certs can hold more information, like &lt;strong&gt;raw strings&lt;/strong&gt; that can be used after the handshake is done. In this case, we have stored the &lt;strong&gt;user/role&lt;/strong&gt; that will be used to log in inside our keys. With this, we can do a pattern match with the certificate content and check if there's any &lt;strong&gt;CN=something&lt;/strong&gt; that matches our &lt;code&gt;select * from system.roles where role = 'something'&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let's start the modifications by entering our ScyllaDB instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enter the ScyllaDB Instance&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla shell

&lt;span class="c"&gt;# root@c531i213hu:/#&lt;/span&gt;
&lt;span class="c"&gt;# Install any editor of your choice&lt;/span&gt;
apt &lt;span class="nb"&gt;install &lt;/span&gt;nano

&lt;span class="c"&gt;# Enter the ScyllaDB Config File&lt;/span&gt;
nano &lt;span class="nt"&gt;-l&lt;/span&gt; /etc/scylla/scylla.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With your config file opened, let's work on the modifications needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.4.1 Change the Authentication Type
&lt;/h4&gt;

&lt;p&gt;This is the last time we'll open this file, I promise! The idea here is to change the authentication type from &lt;code&gt;PasswordAuthenticator&lt;/code&gt; to &lt;code&gt;com.scylladb.auth.CertificateAuthenticator&lt;/code&gt;. We're also going to set a &lt;strong&gt;rule&lt;/strong&gt; that will extract the &lt;code&gt;CN=&lt;/code&gt; flag from each certificate and use the content for authentication purposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;# file: /etc/scylla/scylla.yaml
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;-authenticator: PasswordAuthenticator # line ~247
&lt;/span&gt;&lt;span class="gi"&gt;+authenticator: com.scylladb.auth.CertificateAuthenticator
+auth_certificate_role_queries:
+  - source: SUBJECT
+    query: CN=([^,\s]+)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.4.2 Enable the Encryption Port
&lt;/h4&gt;

&lt;p&gt;We still haven't enabled &lt;strong&gt;TLS/SSL&lt;/strong&gt; even after setting the authenticator. We still need to uncomment the &lt;code&gt;native_transport_port_ssl&lt;/code&gt; to get port 9142 (which is used to transport our encrypted data) into the game. So, back to the &lt;code&gt;scylla.yaml&lt;/code&gt;, lets change it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;# file: /etc/scylla/scylla.yaml
# ...
&lt;span class="gd"&gt;-# native_transport_port_ssl: 9142 # &amp;lt;- line ~131
&lt;/span&gt;&lt;span class="gi"&gt;+native_transport_port_ssl: 9142
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.4.3 Enable the Client Encryption Port
&lt;/h4&gt;

&lt;p&gt;Step by step, we'll make it! Our final change is to the &lt;code&gt;client_encryption_options&lt;/code&gt; as defined in the table above. We need to uncomment everything and make sure everything matches in these configurations. Here's a brief explanation of each configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;enabled:&lt;/strong&gt; enables TLS/SSL encryption -&amp;gt; change to &lt;strong&gt;true&lt;/strong&gt; (default: false)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;certificate:&lt;/strong&gt; &lt;code&gt;absolute path&lt;/code&gt; to your server certificate (security_cert.pem / server_cert.pem)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;keyfile:&lt;/strong&gt; &lt;code&gt;absolute path&lt;/code&gt; your server key signed by the root_key (security_key.pem / server_key.pem)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;truststore:&lt;/strong&gt; &lt;code&gt;absolute path&lt;/code&gt; your server truststore containing server + root certificates (security_truststore.pem / server_truststore.pem)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;require_client_auth:&lt;/strong&gt; your server must receive a certificate to authenticate -&amp;gt; change to true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's work on these changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;# file: /etc/scylla/scylla.yaml
# ...
# enable or disable client/server encryption.
&lt;span class="gd"&gt;-# client_encryption_options:
-#   enabled: true
-#   certificate: /etc/scylla/certs/cert.pem
-#   keyfile: /etc/scylla/certs/key.pem
-#   truststore: /etc/scylla/certs/truststore.pem
-#   require_client_auth: true
&lt;/span&gt;&lt;span class="gi"&gt;+client_encryption_options:
+  enabled: true
+  certificate: /etc/scylla/certs/server_cert.pem
+  keyfile: /etc/scylla/certs/server_key.pem
+  truststore: /etc/scylla/certs/server_truststore.pem
+  require_client_auth: true
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok! Now we're good to go. Let's turn on our ScyllaDB cluster by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; some_scylla supervisorctl start scylla &lt;span class="c"&gt;# Start ScyllaDB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see if our port 9142 is running and listening for TLS/SSL connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; localhost:9042 
&lt;span class="c"&gt;# CONNECTED(00000003)&lt;/span&gt;
&lt;span class="c"&gt;# 40873B60D2750000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:354:&lt;/span&gt;
&lt;span class="c"&gt;# no peer certificate available&lt;/span&gt;
&lt;span class="c"&gt;# No client certificate CA names sent&lt;/span&gt;

openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; localhost:9142
&lt;span class="c"&gt;# CONNECTED(00000003)&lt;/span&gt;
&lt;span class="c"&gt;# Can't use SSL_get_servername&lt;/span&gt;
&lt;span class="c"&gt;# depth=0 CN = server&lt;/span&gt;
&lt;span class="c"&gt;# verify error:num=20:unable to get local issuer certificate&lt;/span&gt;
&lt;span class="c"&gt;# verify return:1&lt;/span&gt;
&lt;span class="c"&gt;# depth=0 CN = server&lt;/span&gt;
&lt;span class="c"&gt;# verify error:num=21:unable to verify the first certificate&lt;/span&gt;
&lt;span class="c"&gt;# verify return:1&lt;/span&gt;
&lt;span class="c"&gt;# depth=0 CN = server&lt;/span&gt;
&lt;span class="c"&gt;# verify return:1&lt;/span&gt;
&lt;span class="c"&gt;# ---&lt;/span&gt;
&lt;span class="c"&gt;# Certificate chain&lt;/span&gt;
&lt;span class="c"&gt;# 0 s:CN = server&lt;/span&gt;
&lt;span class="c"&gt;#   i:CN = administrator&lt;/span&gt;
&lt;span class="c"&gt;#   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256&lt;/span&gt;
&lt;span class="c"&gt;#   v:NotBefore: Aug  1 20:09:38 2024 GMT; NotAfter: Aug  1 20:09:38 2025 GMT&lt;/span&gt;
&lt;span class="c"&gt;# ---&lt;/span&gt;
&lt;span class="c"&gt;# YAY IT'S ASKING FOR CERTIFICATES!!!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we are 100% sure that TLS is enabled and requesting the certificates that match our previously generated keys. &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Testing Encrypted Connections
&lt;/h2&gt;

&lt;p&gt;Too much stuff to configure, but how do we connect to it? Instead of using CQLSH (because it's a pain in the ass to set it up and &lt;a href="https://github.com/Daniel-Boll/scylla-javascript-driver/pull/34" rel="noopener noreferrer"&gt;I LITERALLY PREFERED TO MAKE IT WORK&lt;/a&gt; on Node than explain how to use it), we're going to use NodeJS for the sake of simplicity.&lt;/p&gt;

&lt;p&gt;First, let's quick setup our driver by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @lambda-group/scylladb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you can already create a demo script pointing your nodes and don't forget to switch the ports at the connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Cluster&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@lambda-group/scylladb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
    &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;127.0.0.1:9142&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="na"&gt;truststoreFilepath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/your/path/to/certificates/developer_cert.pem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="na"&gt;privateKeyFilepath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/your/path/to/certificates/developer_key.pem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="na"&gt;caFilepath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/your/path/to/certificates/developer_truststore.pem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="na"&gt;verifyMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VerifyMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Peer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="p"&gt;}});&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT address, port, username, driver_name, driver_version FROM system.clients&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// [&lt;/span&gt;
&lt;span class="c1"&gt;//  {&lt;/span&gt;
&lt;span class="c1"&gt;//     address: '127.0.0.1',&lt;/span&gt;
&lt;span class="c1"&gt;//     driver_name: 'scylla-js-driver',&lt;/span&gt;
&lt;span class="c1"&gt;//     driver_version: '0.0.1',&lt;/span&gt;
&lt;span class="c1"&gt;//     port: 58846,&lt;/span&gt;
&lt;span class="c1"&gt;//     username: 'developer' // We're logged in as the role 'developer'&lt;/span&gt;
&lt;span class="c1"&gt;//  }&lt;/span&gt;
&lt;span class="c1"&gt;// ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the output tells us, we managed to connect by only sending our key and certificate to the server! &lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusion
&lt;/h2&gt;

&lt;p&gt;This "article/tutorial" took me a long time to write for several reasons, but one of them was to make sure of the content by going through it a few times.&lt;/p&gt;

&lt;p&gt;I also made a &lt;a href="https://github.com/DanielHe4rt/scylladb-role-tls-auth" rel="noopener noreferrer"&gt;demo (gh: danielhe4rt/scylladb-role-tls-auth)&lt;/a&gt; where you can run a &lt;code&gt;makefile&lt;/code&gt; command and set up all these steps. So if you got here somehow, please don't forget to drop a star :D&lt;/p&gt;

&lt;p&gt;Security is one of the topics that people are starting to pay more attention to nowadays and learning more about it was very exciting. Anyway, let me know what topics you would like to see in this series!&lt;/p&gt;

&lt;p&gt;Stay safe and don't forget to drink water!&lt;/p&gt;

</description>
      <category>scylladb</category>
      <category>database</category>
      <category>tutorial</category>
      <category>security</category>
    </item>
    <item>
      <title>Laravel inside Rust? I have a reason for that.</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Mon, 26 Feb 2024 14:22:06 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/laravel-inside-rust-i-have-a-reason-for-that-ke3</link>
      <guid>https://forem.com/danielhe4rt/laravel-inside-rust-i-have-a-reason-for-that-ke3</guid>
      <description>&lt;p&gt;What's up everyone!&lt;/p&gt;

&lt;p&gt;I've been study Rust for the last couple of months and always trying to get closer of my actual stack which is around Laravel environment. &lt;/p&gt;

&lt;p&gt;For me, as a PHP Developer, jump into Rust is a truly hard task since I never went to Functional Programming before, however I found a way to make this "easier". &lt;/p&gt;

&lt;h2&gt;
  
  
  Rust AFAIK
&lt;/h2&gt;

&lt;p&gt;The whole ecosystem is made up of different packages and you should add it as you need it, unlike Laravel which has a really robust environment around the framework.&lt;/p&gt;

&lt;p&gt;So my first impression was that I had to learn how to use the base packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dotenvy&lt;/li&gt;
&lt;li&gt;Chrono&lt;/li&gt;
&lt;li&gt;Time&lt;/li&gt;
&lt;li&gt;Uuid&lt;/li&gt;
&lt;li&gt;and so on. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But when it comes to Web Development (API mostly) you have to choose an framework among many which is already there. Like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actix (currently using)&lt;/li&gt;
&lt;li&gt;Axum (evaluating)&lt;/li&gt;
&lt;li&gt;Rocket (people always tell me to not use it, still don't know why)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and none of them has the opinionated "structure" of Laravel, so I decided to create mine. &lt;/p&gt;

&lt;h2&gt;
  
  
  Laravel inside Rust
&lt;/h2&gt;

&lt;p&gt;Why am I talking about Laravel? Because the "MVC" structure it gives us is elegant enough for small projects with Rust Web.&lt;/p&gt;

&lt;p&gt;Things started to make sense when I coded Rust using the opinionated  Laravel framework. Here's a structure of what I'm talking about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./src
├── app.rs
├── config.rs
├── http
│   ├── controllers
│   │   ├── leaderboard_controller.rs
│   │   ├── mod.rs
│   │   └── submissions_controller.rs
│   ├── mod.rs
│   └── requests
│       ├── leaderboard_request.rs
│       ├── mod.rs
│       └── submission_request.rs
├── main.rs
├── models
│   ├── leaderboard.rs
│   ├── mod.rs
│   └── submission.rs
└── repositories
    ├── leaderboard_repository.rs
    ├── mod.rs
    └── submission_repository.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This project is currently using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://actix.rs/docs/" rel="noopener noreferrer"&gt;Actix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nodecosmos/charybdis" rel="noopener noreferrer"&gt;Charybdis ORM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and you can check my mess in this &lt;a href="https://github.com/DanielHe4rt/leaderboard-rust/pull/1" rel="noopener noreferrer"&gt;Pull Request&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The question is: would be a good thing to follow this thoughts while working with Rust? The simplicity and good structure for maintaining is what I'm always looking in a project. &lt;/p&gt;

&lt;p&gt;Also I'm thinking to write some series on how is my process migrating from PHP to Rust, would interest you read something like that?&lt;/p&gt;

&lt;p&gt;Hope to see your thoughts here and thanks!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>laravel</category>
      <category>rust</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What we've achieved with 1 Month of Basement Devs</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Mon, 19 Feb 2024 15:29:22 +0000</pubDate>
      <link>https://forem.com/basementdevs/what-weve-achieved-with-1-month-of-basement-devs-3pec</link>
      <guid>https://forem.com/basementdevs/what-weve-achieved-with-1-month-of-basement-devs-3pec</guid>
      <description>&lt;p&gt;Running a community is a tough job, but after a few years of doing it, it becomes an easy task. This is the first month of our community and I want to show you what we have accomplished so far.&lt;/p&gt;

&lt;p&gt;If you're planning to run a community or even join one, this series will show you how to measure the health of the community using &lt;a href="https://discord.gg/basementdevs" rel="noopener noreferrer"&gt;Basement Developers&lt;/a&gt; as an example. &lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. General Achievements&lt;/li&gt;
&lt;li&gt;
2. Demographics

&lt;ul&gt;
&lt;li&gt;2.1 New Members&lt;/li&gt;
&lt;li&gt;2.2 Members Activation&lt;/li&gt;
&lt;li&gt;2.3 Member Visits &amp;amp; Comunicators&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;3. Events&lt;/li&gt;

&lt;li&gt;4. Partnerships&lt;/li&gt;

&lt;li&gt;5. Published Content&lt;/li&gt;

&lt;li&gt;6. What now?&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. General Achievements
&lt;/h2&gt;

&lt;p&gt;First of all, I'd like to thank a few readers who joined the community. Now we have a couple of Polish people who engage there on a daily basis. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;FYI: the community is looking for members like you, so join us ASAP! :D&lt;/p&gt;
&lt;/blockquote&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%2Fq0zly7fwr9rjijsuz832.jpg" 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%2Fq0zly7fwr9rjijsuz832.jpg" alt="Weekly Meeting with a peak of 71 members" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;Peak of 71 members in our latest weekly meeting.&lt;/center&gt;



&lt;p&gt;Since we started the community, our weekly meetings have been the place to discuss new opportunities, projects, and other opportunities down there, and to listen to what the members have to say.&lt;/p&gt;


  
  Your browser does not support the video tag.
 

&lt;p&gt;Speaking of community feedback, most of our members are Brazilians who want to get used to English, so the first project made in the community was an overlay to translate everything we say in our weekly meetings from English to Brazilian-Portuguese! Cheers to &lt;a href="https://github.com/Pantotone" rel="noopener noreferrer"&gt;Pantotone&lt;/a&gt;, the creator of this amazing tool!&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%2Fyv2brtina8dtrd1ifqb0.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%2Fyv2brtina8dtrd1ifqb0.png" alt="Github Organization" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, since we're starting to create projects, a new GitHub organization has been created to host all projects related to our community. Don't forget to &lt;a href="https://github.com/basementdevs" rel="noopener noreferrer"&gt;follow our community&lt;/a&gt; to get the latest project updates!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Demographics
&lt;/h2&gt;

&lt;p&gt;When we talk about growth, we talk about numbers! Here's a recap from &lt;strong&gt;January 14 to February 12&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 New Members
&lt;/h3&gt;

&lt;p&gt;Since January 15th we have doubled the number of members! Currently we have 2197 active members on the server and many of them are practicing English every day in voice channels (in groups or one-on-one) and text channels of different styles.&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%2Fw1dqorxb9zx3gl86iug7.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%2Fw1dqorxb9zx3gl86iug7.png" alt="Chart with peak of 2k members" width="670" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Members Activation
&lt;/h3&gt;

&lt;p&gt;One of the metrics we'll be working on this month is the "activation" of a new member, which is when they understand what the community is about and why it's a good fit for them.&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%2Fzmjkzxh5d2te1gzmbl1y.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%2Fzmjkzxh5d2te1gzmbl1y.png" alt="Chart of new members interacting over the last month" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We did great in the first month and you can see the graph going straight to the bottom, but that's just because this last week we had &lt;strong&gt;Carnaval&lt;/strong&gt; here in Brazil, so it was expected and our Brazilian developers deserve this amazing event and a good vacation.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Member Visits &amp;amp; Comunicators
&lt;/h3&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%2F7xs7vtuw8fyd1h5ldfbq.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%2F7xs7vtuw8fyd1h5ldfbq.png" alt="Chart of member visits over the month" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our average number of communicators or engagement is 8%. Our goal is to get to 15% by the end of March. How are we going to do that? I don't know yet, but with this list of weekly events, it should be a good bet.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Events
&lt;/h2&gt;

&lt;p&gt;Events are at the heart of our community, and last month, 16 pre-scheduled events were held, divided into 5 models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Basement Meeting:&lt;/strong&gt; Our weekly meeting held every Tuesday at 07:00 PM BRT. Its purpose is to share the plans of our community, announce new partnerships, update members on news, and of course, practice English.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Practicing with Renato:&lt;/strong&gt; Every Wednesday, our community gathers to practice English with Renato. In this practice session, our members are given a topic, and each one engages in a conversation with Renato about it, always introducing new words to expand the community's vocabulary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Traveling with JP:&lt;/strong&gt; In this session, our members will plan their dream trip together with JP, discussing costs, places to visit, local food, and much more! Come and plan your trip with us.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Practice with Leonardo:&lt;/strong&gt; Every Thursday morning, our community participates in an English practice session with Leonardo. Participants are assigned a topic and engage in conversation with Leonardo, incorporating new words to build vocabulary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Coding Dojo:&lt;/strong&gt; In early February, we launched the Basement Coding Dojo, an event where community members take on roles in a development team during a simulated sprint. Our first Dojo Dev Team is made up of &lt;a href="https://github.com/gvieiragoulart" rel="noopener noreferrer"&gt;Gabriel&lt;/a&gt;, &lt;a href="https://github.com/Lorenalgm" rel="noopener noreferrer"&gt;Lorena&lt;/a&gt;, &lt;a href="https://github.com/lucas-pace" rel="noopener noreferrer"&gt;Lucas&lt;/a&gt;, &lt;a href="https://github.com/pedrovian4" rel="noopener noreferrer"&gt;Pedro&lt;/a&gt;, &lt;a href="https://github.com/reenatoteixeira" rel="noopener noreferrer"&gt;Renato&lt;/a&gt; and &lt;a href="https://github.com/yurastico" rel="noopener noreferrer"&gt;Yuri&lt;/a&gt;. Over the course of a month, the team aims to build a simple but complete application, working on design, backend and frontend, attending weekly meetings and interacting with an open-source project. You can find more information about this event in &lt;a href="https://github.com/basementdevs/english-coding-dojo" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Partnerships
&lt;/h2&gt;

&lt;p&gt;Right now our biggest goal is to find HR companies or even companies that are actively recruiting developers. &lt;/p&gt;

&lt;p&gt;For this month, our goal is to build a demographic with more information about things that will be interesting to bring these opportunities to our members, e.g: Seniority, Stack and others. So far we have some results, but nothing that's meaningful yet, since it's a new approach on our side.&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%2Fbxll9ud9we8y6uo1miry.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%2Fbxll9ud9we8y6uo1miry.png" alt="User Early Demographics" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have an open position in your company, please email me at &lt;a href="mailto:danielhe4rt@gmail.com"&gt;danielhe4rt@gmail.com&lt;/a&gt; and I'll forward it to our best members to apply! &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Published Content
&lt;/h2&gt;

&lt;p&gt;During the last month, members of our community have received several recognitions for the articles produced on this platform. We would like to highlight the following articles, which were among the most relevant articles of their posting weeks (Top 7).&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/scylladb" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F9699%2F39631723-ec7f-4687-8b0d-56ce667e5742.png" alt="ScyllaDB" width="594" height="789"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F468493%2F330b0830-a179-4560-9b47-623cd8abeac8.png" alt="" width="512" height="512"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/scylladb/database-101-how-to-model-leaderboards-for-1m-players-game-2pfa" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Database 101: How to Model Leaderboards for 1M Player's Game.&lt;/h2&gt;
      &lt;h3&gt;Daniel Reis for ScyllaDB ・ Jan 29 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#scylladb&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#database&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#yarg&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;"In the latest installment of his "Database 101" series, &lt;a class="mentioned-user" href="https://dev.to/danielhe4rt"&gt;@danielhe4rt&lt;/a&gt; explores the intricate art of modeling leaderboards for games with a million players. Drawing on personal experiences with the open-source rhythm game YARG and leveraging ScyllaDB's efficiency, the article delves into Query Driven Data Modeling and wide-column database concepts, providing a comprehensive guide for crafting performative leaderboards."&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/basementdevs" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F8357%2F7f9488ac-1969-477c-be09-1f36cd61420d.png" alt="Basement Developers" width="512" height="512"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F1257274%2F12a280c7-7a40-4ddc-8e04-bb692e0ce473.png" alt="" width="800" height="800"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/basementdevs/everything-that-you-need-to-know-about-git-2440" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Everything you need to know about GIT&lt;/h2&gt;
      &lt;h3&gt;Renato Teixeira for Basement Developers ・ Feb 5 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#learning&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#git&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;"Discover the world of code versioning with GIT through this comprehensive beginner's guide! Authored by first-time DEV contributor &lt;a class="mentioned-user" href="https://dev.to/reenatoteixeira"&gt;@reenatoteixeira&lt;/a&gt;, this breakout article meticulously unpacks all the essentials of GIT, ensuring a smooth learning journey. With crystal-clear explanations and detailed step-by-step instructions, you'll master the art of GIT, empowering you with seamless version control capabilities."&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/kecbm" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F846886%2F3661bc21-5c36-4c21-b49d-a07cd28718f1.png" alt="kecbm"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/kecbm/staircase-detail-112g" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Staircase detail&lt;/h2&gt;
      &lt;h3&gt;Klecianny Melo ・ Feb 16 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#learning&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Discover how to build staircases in programming for beginners with this fantastic step-by-step tutorial created by our contributor @kebcm! A staircase is a visual representation formed by a series of steps, each represented by the # character. Explore how to create a function that prints a custom-sized staircase.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/basementdevs" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F8357%2F7f9488ac-1969-477c-be09-1f36cd61420d.png" alt="Basement Developers" width="512" height="512"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F521662%2F2d86c6c2-9f3e-457b-a6de-e69ddfb4733c.png" alt="" width="397" height="397"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/basementdevs/be-a-better-developer-with-these-git-good-practices-2dim" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Be a better developer with these Git good practices&lt;/h2&gt;
      &lt;h3&gt;Anthony Vinicius for Basement Developers ・ Feb 16 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#git&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#github&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;If you're a developer, you likely use Git regularly. It's vital for app development, whether solo or in a team. But many struggle with messy repositories and unclear commit messages / branch names. Learning Git well and sticking to best practices is one of the keys for career growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. What now?
&lt;/h2&gt;

&lt;p&gt;So far our community is growing in a way we didn't expect, but still in a healthy way. Many people who have never tried &lt;strong&gt;Technical English&lt;/strong&gt; before have taken their first steps to practice and have begun to &lt;strong&gt;glimpse new possibilities&lt;/strong&gt;, and that's the fuel we need.&lt;/p&gt;

&lt;p&gt;If you want to be a part of this transformative journey, please join our &lt;a href="https://discord.gg/basementdevs" rel="noopener noreferrer"&gt;Discord Server&lt;/a&gt; and don't forget to like and comment on this article! &lt;/p&gt;

&lt;p&gt;Any tip to make our community better is welcome, ok? Stay hydrate and see you next month!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Btw, cheers to &lt;strong&gt;Renato&lt;/strong&gt; and &lt;strong&gt;Anthony&lt;/strong&gt; for helping me on this report :D&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>devrel</category>
      <category>community</category>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Database 101: How to Model Leaderboards for 1M Player's Game.</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Mon, 29 Jan 2024 17:34:16 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/database-101-how-to-model-leaderboards-for-1m-players-game-2pfa</link>
      <guid>https://forem.com/danielhe4rt/database-101-how-to-model-leaderboards-for-1m-players-game-2pfa</guid>
      <description>&lt;p&gt;Ever wondered how a game like &lt;strong&gt;League of Legends&lt;/strong&gt;, &lt;strong&gt;Fortnite&lt;/strong&gt;, or even &lt;strong&gt;Rockband&lt;/strong&gt; models its leaderboards? In this article, we'll find out how to properly model a schema to handle them in a monstrously performative way!&lt;/p&gt;

&lt;p&gt;If you’re just getting started with databases in general or databases, you might want to start off by reading my initial post, &lt;a href="https://dev.to/danielhe4rt/database-101-why-so-interesting-1344"&gt;Database 101: Data Consistency for Beginners&lt;/a&gt; for Beginners. That article captures my own exploration of how many database paradigms exist as I look far beyond my previous experience with just SQL and MySQL. I’m keeping track of my studies in this &lt;strong&gt;Database 101&lt;/strong&gt; series.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It has been almost a year since I published my first article in this series! Thank you for being here with me as I learn this subject. Your comments and thoughts are always very helpful!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Prologue
&lt;/h2&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%2Fdvensca2v67ma66vssnh.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%2Fdvensca2v67ma66vssnh.png" alt="YARG Game Playthrough ScreenShot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ever since I was a kid, like most average developers, I've been fascinated by games and how they're made. Speaking of which, let me introduce you to my favorite childhood game:  Guitar Hero 3: Legends of Rock. &lt;/p&gt;

&lt;p&gt;Well, more than a decade later, I decided to try to contribute with some games in the open source environment, like &lt;a href="https://github.com/nmeylan/rust-ro" rel="noopener noreferrer"&gt;rust-ro (Rust Ragnarok Emulator)&lt;/a&gt; and also the main character of this article: the &lt;a href="https://github.com/YARC-Official/YARG" rel="noopener noreferrer"&gt;YARG (Yet Another Rhythm Game)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;YARG is literally another rhythm game, but the difference about this project is that it is completely &lt;strong&gt;open source&lt;/strong&gt; and they united legendary contributors in game development and also design to make this project works. &lt;/p&gt;

&lt;p&gt;Suddenly the game was being picked up and played mostly by Guitar Hero/Rockband streamers on Twitch, and I thought: well, it's an open source project, so maybe I can use my database skills for something like creating a &lt;strong&gt;monstrously fast leaderboard&lt;/strong&gt; or store the past games. &lt;/p&gt;

&lt;p&gt;It started as a simple chat on their Discord, which turned into a long discussion about how to make this project grow faster. &lt;/p&gt;

&lt;p&gt;Then I decided to talk to my boss and ask him if I could work with the YARG guys and the condition was to create something cool enough to implement &lt;a href="https://scylladb.com/" rel="noopener noreferrer"&gt;ScyllaDB (NoSQL Wide-column Database)&lt;/a&gt; since I'm working as a Developer Advocate there. You won't believe how the simplicity and scalability brought by ScyllaDB perfectly fit the needs of YARG.in!&lt;/p&gt;

&lt;p&gt;Anyway, talk is cheap. Let me show you some code and concepts!&lt;/p&gt;

&lt;h2&gt;
  
  
  2.  QDD - Query Driven Data Modeling
&lt;/h2&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%2Fivkj9j8ni2fakkctx53n.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%2Fivkj9j8ni2fakkctx53n.png" alt="NoSQL vs Relational" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we're talking about develop with &lt;strong&gt;NoSQL&lt;/strong&gt;, mostly we should understand that depending on the paradigm (document, graph, wide-column etc) you should first understand &lt;strong&gt;which query you want to run&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;While in MySQL the main goal is to understand the consistency, in Scylla you should focus on the query and create your schema based on that query.&lt;/p&gt;

&lt;p&gt;At this project, we will handle two types of paradigm, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key-Value&lt;/li&gt;
&lt;li&gt;Wide Column (Clusterization)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's talk about the queries/features of our modeling.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Feature: Storing the matches
&lt;/h3&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%2Fjaw4q7349upgrsa5p5g3.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%2Fjaw4q7349upgrsa5p5g3.png" alt="Submission Details YARG" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time that you finish a YARG gameplay, the most interest thing would be submitting your scores together with many other in-game metrics. &lt;/p&gt;

&lt;p&gt;Basically it will be a single query based in a main index and that's all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;missed_notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;  
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submisisons&lt;/span&gt;  
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;submission_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'some-uuid-here-omg'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.2 Feature: Leaderboard
&lt;/h3&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%2F69jp0vgxef71titt9ks0.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%2F69jp0vgxef71titt9ks0.png" alt="Leaderboard Figma File" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now our main goal: a super cool &lt;strong&gt;leaderboard&lt;/strong&gt; that you don't need to care about after a good data modeling. The leaderboard is per song, so every time you play a specific song, your best score will be saved and ranked. &lt;/p&gt;

&lt;p&gt;However there's a big point on this interface, which is having filters to know exactly "which" leaderboard to bring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;song_id: required&lt;/li&gt;
&lt;li&gt;instrument: required&lt;/li&gt;
&lt;li&gt;modifiers: required&lt;/li&gt;
&lt;li&gt;difficulty: required&lt;/li&gt;
&lt;li&gt;player_id: optional&lt;/li&gt;
&lt;li&gt;score: optional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So imagine our query looks like this, and it returns the results sorted by score in descending order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'guitar'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'expert'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'dani-california'&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; 
    &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;--   player_id  | score&lt;/span&gt;
&lt;span class="c1"&gt;----------------+-------&lt;/span&gt;
&lt;span class="c1"&gt;--        tzach | 12000&lt;/span&gt;
&lt;span class="c1"&gt;--  danielhe4rt | 10000&lt;/span&gt;
&lt;span class="c1"&gt;--     kadoodle |  9999&lt;/span&gt;
&lt;span class="c1"&gt;----------------+-------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we know the features that will be worked here, but can you already imagine how will be the final schema? &lt;/p&gt;

&lt;p&gt;No? Ok, lemme help you on that!&lt;/p&gt;

&lt;h2&gt;
  
  
  3.  Data Modeling time!
&lt;/h2&gt;

&lt;p&gt;Time to take a deep dive into data modeling with ScyllaDB and better understand how to scale it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 - Matches Modeling
&lt;/h3&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%2Fb6kedk7iu67zg7myj9mp.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%2Fb6kedk7iu67zg7myj9mp.png" alt="End Game Screen" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, let us understand a little more about the game itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's a rhythm game;&lt;/li&gt;
&lt;li&gt;You play a certain song at a time;&lt;/li&gt;
&lt;li&gt;You can activate "modifiers" to make your life easier or harder before the game;&lt;/li&gt;
&lt;li&gt;You have to choose an instrument (e.g. guitar, drums, bass and microphone).&lt;/li&gt;
&lt;li&gt;Every aspect of the gameplay is tracked, such as:

&lt;ul&gt;
&lt;li&gt;Score;&lt;/li&gt;
&lt;li&gt;Missed notes;&lt;/li&gt;
&lt;li&gt;Overdrive count;&lt;/li&gt;
&lt;li&gt;Play speed (1.5x ~ 1.0x);&lt;/li&gt;
&lt;li&gt;Date/time of gameplay;&lt;/li&gt;
&lt;li&gt;And other cool stuff.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Thinking on that, we can easily start our data modeling, which will turn in something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submissions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;submission_id&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;player_id&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stars&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;accuracy_percentage&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;missed_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ghost_notes_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_combo_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;overdrive_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;played_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;submission_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;played_at&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;Let's skip all the &lt;code&gt;int/text&lt;/code&gt; values and jump to the &lt;code&gt;set&amp;lt;text&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;set&lt;/strong&gt; type allows you to store a list of items of a particular type. I decided to use this list to store the modifiers because it's a perfect fit. Look at how the queries are executed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submissions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;submission_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;track_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;played_at&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;some&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cool&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'all-taps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'hell-mode'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'no-hopos'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s1"&gt;'2024-01-01 00:00:00'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this type, you can easily store a list of items to retrieve later. &lt;/p&gt;

&lt;p&gt;Another cool piece of information is that this query is a key-value like! What does that mean? &lt;/p&gt;

&lt;p&gt;Since you will always query it by the &lt;code&gt;submission_id&lt;/code&gt; only, it can be categorized as a key-value.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Leaderboard Modeling
&lt;/h3&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%2Flpmzngra3jk5ipf3os3i.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%2Flpmzngra3jk5ipf3os3i.png" alt="Leaderboard filters Figma" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the part of the article where you will learn some cool wide-column database concepts.&lt;/p&gt;

&lt;p&gt;On our leaderboard query, as mentioned earlier, we will always need some dynamic values in the WHERE clauses, which means that these values will belong to the &lt;strong&gt;Partition Key&lt;/strong&gt; while the &lt;strong&gt;Clustering Keys&lt;/strong&gt; will have value that can be "optional". &lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;partition key&lt;/strong&gt; is a hash based on a &lt;strong&gt;combination of fields&lt;/strong&gt; that you added to identify a value. Did you get it? No? Well, it took me a while to understand that too, but let me show you something:&lt;/p&gt;

&lt;p&gt;Let's imagine that you played &lt;code&gt;Starlight - Muse&lt;/code&gt; 100x times. If you would query this information, would be 100x different results differentiated by Clustering Keys like &lt;code&gt;score&lt;/code&gt; or &lt;code&gt;player_id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="c1"&gt;---&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; 
    &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If 1.000.000 players play this song, your query will become slow and it will become a problem in the future, because your partition key consists of only one field, which is &lt;code&gt;track_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, if you add more fields to your &lt;strong&gt;Partition Key&lt;/strong&gt;, like mandatory things before playing the game, maybe we can shrink these possibilities for a faster query. Now you see the big picture? Adding the fields like: &lt;strong&gt;Instrument&lt;/strong&gt;, &lt;strong&gt;Difficulty&lt;/strong&gt; and &lt;strong&gt;Modifiers&lt;/strong&gt; will give you a way to split the information about that specific track evenly.&lt;/p&gt;

&lt;p&gt;Let's imagine with some simple numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="c1"&gt;-- Query Partition ID: '1'&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'guitar'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'expert'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; 
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="c1"&gt;-- Modifiers Changed&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; 
    &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Query Partition ID: '2'&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'guitar'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'expert'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'all-hopos'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="c1"&gt;-- Modifiers Changed&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; 
    &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, if you build the query in a specific shape it will always look for a specific token and retrieve the data based on these specifics Partition Keys.&lt;/p&gt;

&lt;p&gt;Let's take a look at the final modeling and talk about the clustering keys and the application layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;submission_id&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;player_id&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stars&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;accuracy_percentage&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;missed_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ghost_notes_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_combo_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;overdrive_count&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;played_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;track_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;modifiers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;difficulty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;CLUSTERING&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;player_id&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The partition key was defined as mentioned above, consisting of our &lt;strong&gt;REQUIRED PARAMETERS&lt;/strong&gt; such as: track_id, modifiers, difficulty and instrument. And on the &lt;strong&gt;Clustering Keys&lt;/strong&gt; we added &lt;strong&gt;score&lt;/strong&gt; and &lt;strong&gt;player_id&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that by default the clustering fields are ordered by &lt;code&gt;score DESC&lt;/code&gt; and just in case a player has the same score, the criteria to choose the winner will be &lt;code&gt;alphabetical&lt;/code&gt; ¯\&lt;em&gt;(ツ)&lt;/em&gt;/¯.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First is good to understand that we will have only &lt;strong&gt;ONE SCORE PER PLAYER&lt;/strong&gt;, but with this modeling like that if the player goes through the same track twice in different scores, it will generate two different entries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;played_at&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'daniel-reis'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="mi"&gt;133700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'expert'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'guitar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'2023-11-23 00:00:00'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;played_at&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'daniel-reis'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="mi"&gt;123700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'expert'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'guitar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="s1"&gt;'2023-11-23 00:00:00'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;player_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'guitar'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'expert'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt; 
&lt;span class="k"&gt;LIMIT&lt;/span&gt; 
    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;--   player_id  | score&lt;/span&gt;
&lt;span class="c1"&gt;----------------+-------&lt;/span&gt;
&lt;span class="c1"&gt;--  daniel-reis | 133700&lt;/span&gt;
&lt;span class="c1"&gt;--  daniel-reis | 123700&lt;/span&gt;
&lt;span class="c1"&gt;----------------+-------&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how do we fix this problem? Well, it's not a problem per se. It's a feature! LOL&lt;/p&gt;

&lt;p&gt;As a developer, you have to create your own business rules based on the project needs, and this is no different. What do I mean by that?&lt;/p&gt;

&lt;p&gt;You can run a simple &lt;strong&gt;DELETE&lt;/strong&gt; query before insert the new entry and guarantee that you will not have a specific data from the &lt;strong&gt;player_id&lt;/strong&gt; with less than the new &lt;strong&gt;score&lt;/strong&gt; inside that specific group of &lt;strong&gt;partition keys&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Before Insert the new Gampleplay&lt;/span&gt;

&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="n"&gt;leaderboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;song_leaderboard&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;instrument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'guitar'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;difficulty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'expert'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;modifiers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'starlight-muse'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;player_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'daniel-reis'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="s1"&gt;'your-new-score-here'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Now you can insert the new payload...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that we finished our simple leaderboard system, the same one that runs in YARG and can also be used in games with MILLIONS of entries per second :D&lt;/p&gt;

&lt;h2&gt;
  
  
  4. How to Contribute to YARG
&lt;/h2&gt;

&lt;p&gt;Here's the part of the text that I'll invite you to contribute on this wonderful open source project!&lt;/p&gt;

&lt;p&gt;Today we're building a brand new platform for all the players using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Game: Unity3d &lt;a href="https://github.com/YARC-Official/YARG" rel="noopener noreferrer"&gt;(Repository)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Front-end: NextJS &lt;a href="https://github.com/YARC-Official/yarg.in" rel="noopener noreferrer"&gt;(Repository)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Back-end: Laravel 10.x &lt;a href="https://github.com/YARC-Official/yarg-api" rel="noopener noreferrer"&gt;(Repository)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and we will need many developers and testers as possible to discuss future implementations of the game together with the main contributors!&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%2Fy5b2pdxvrth2o6jfmada.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%2Fy5b2pdxvrth2o6jfmada.png" alt="YARG Discord" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, make sure to join their &lt;a href="https://discord.gg/sqpu4R552r" rel="noopener noreferrer"&gt;Discord Community&lt;/a&gt;. There is the place where all the technical discussions happen with the back of the community before going to the development board.&lt;/p&gt;

&lt;p&gt;Also, outside of Discord, the YARG community is mostly focused on the &lt;a href="https://twitter.com/EliteAsian123" rel="noopener noreferrer"&gt;EliteAsian&lt;/a&gt; (core contributor and project owner) Twitter account for development showcases. Be sure to follow him there as well.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1736149319382671766-123" src="https://platform.twitter.com/embed/Tweet.html?id=1736149319382671766"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1736149319382671766-123');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1736149319382671766&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;And FYI, the &lt;strong&gt;Lead Artist&lt;/strong&gt; of the game, aka &lt;a href="https://twitter.com/kaduyarg" rel="noopener noreferrer"&gt;Kadu&lt;/a&gt; is also a &lt;strong&gt;Broadcast Specialist&lt;/strong&gt; and &lt;strong&gt;Product Innovation&lt;/strong&gt; Developer at &lt;strong&gt;Elgato&lt;/strong&gt; that worked with streamers like: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ninja &lt;/li&gt;
&lt;li&gt;Nadeshot &lt;/li&gt;
&lt;li&gt;StoneMountain64&lt;/li&gt;
&lt;li&gt;and the legendary DJ Marshmello.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kadu also use his twitter to share some insights and early previews of new features and experimentations for YARG. So, don't forget to follow him on Twitter as well!&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1689489132060397568-629" src="https://platform.twitter.com/embed/Tweet.html?id=1689489132060397568"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1689489132060397568-629');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1689489132060397568&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Here is some useful links to know more about the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://yarg.in/" rel="noopener noreferrer"&gt;Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/YARC-Official/YARG" rel="noopener noreferrer"&gt;Github Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yarg.youtrack.cloud/agiles/147-7/current" rel="noopener noreferrer"&gt;Task Board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Fun fact: YARG got noticed by &lt;a href="https://twitter.com/BrianBright/status/1744533504531317194" rel="noopener noreferrer"&gt;Brian Bright&lt;/a&gt;, project lead on Guitar Hero, who liked the fact that the project was open source. Awesome, right?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Conclusion
&lt;/h2&gt;

&lt;p&gt;Data modeling is sometimes challenging, and this study took 3 months of many new ScyllaDB concepts and a lot of testing together with my community at Twitch. &lt;/p&gt;

&lt;p&gt;I have also published a &lt;a href="https://github.com/scylladb/gaming-leaderboard-demo" rel="noopener noreferrer"&gt;Gaming Leaderboard Demo&lt;/a&gt;, where you can get some insights on how to implement the same project using &lt;strong&gt;NextJS&lt;/strong&gt; and &lt;strong&gt;ScyllaDB&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Also, if you liked ScyllaDB and want to learn more about, I strongly suggest you to watch our free &lt;a href="https://lp.scylladb.com/masterclass-ondemand-main?siteplacement=navigation" rel="noopener noreferrer"&gt;Masterclass Courses&lt;/a&gt; or vising &lt;a href="https://university.scylladb.com/" rel="noopener noreferrer"&gt;ScyllaDB University&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Don't forget to like this post, follow me on the socials and fill your water bottle xD &lt;/p&gt;

&lt;p&gt;See you in the next article!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/danielhe4rt" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/danielhe4rt" rel="noopener noreferrer"&gt;Follow me on Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitter.com/danielhe4rt" rel="noopener noreferrer"&gt;Follow me on Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://twitch.tv/danielhe4rt" rel="noopener noreferrer"&gt;Follow and Subscribe at my Twitch Channel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>scylladb</category>
      <category>database</category>
      <category>yarg</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Translating Database Queries</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Sun, 28 Jan 2024 16:01:37 +0000</pubDate>
      <link>https://forem.com/danielhe4rt/translating-database-queries-3n0m</link>
      <guid>https://forem.com/danielhe4rt/translating-database-queries-3n0m</guid>
      <description>&lt;p&gt;Did you ever wondered a tool that can be translating many database syntax's at the same time? &lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Prologue&lt;/li&gt;
&lt;li&gt;2. Once upon a time&lt;/li&gt;
&lt;li&gt;3. Translating SQL&lt;/li&gt;
&lt;li&gt;4. Final Considerations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prologue
&lt;/h2&gt;

&lt;p&gt;I've been working professionally as a developer since 2018, and one of the hardest things to decide when I decided to start writing feature tests was: which database should I use as the base for our test cases?&lt;/p&gt;

&lt;p&gt;Why do I say this? I mean, most of the tutorials on the internet at that time tell us to use SQLITE, which is strange since you probably don't run it in production.&lt;/p&gt;

&lt;p&gt;As far as I can remember, videos and articles creating CRUD solutions using PHP, C#, Java and Python point directly to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oracle&lt;/li&gt;
&lt;li&gt;MariaDB&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and of course that there's a lot of differentiation on these databases syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Once upon a time
&lt;/h2&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%2Fs1cz4xv5gv61ngm6tj1b.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%2Fs1cz4xv5gv61ngm6tj1b.png" alt="Image description" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is one of many scripts that I decided to convert between SQLITE and MySQL in a very specific project and I can tell you that is a PAIN IN THE ASS!&lt;/p&gt;

&lt;p&gt;Being a junior/mid level developer getting weird tasks that might not be the best approach to solve a problem sucks totally, mostly because you have to stop and study the differences between databases and their syntax with a short deadline.&lt;/p&gt;

&lt;p&gt;Since the &lt;a href="https://www.iso.org" rel="noopener noreferrer"&gt;ISO (International Organization for Standardization)&lt;/a&gt; and &lt;a href="https://www.ansi.org/" rel="noopener noreferrer"&gt;ANSI (American National Standards Institute)&lt;/a&gt; have decided that if you want to implement the SQL standard, you HAVE to implement the function, the name of the function itself doesn't really matter. Right? RIGHT??&lt;/p&gt;

&lt;p&gt;Aggregators, functions and any other type of syntax related can be written in different styles and since it's implemented following the SQL-92 standards, will be recognized as an SQL database. &lt;/p&gt;

&lt;p&gt;Take a look at the script below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Enabling Foreign Keys in different databases&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINTS&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;DEFERRED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- PostgreSQL&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;FOREIGN_KEY_CHECKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- MySQL&lt;/span&gt;
&lt;span class="n"&gt;PRAGMA&lt;/span&gt; &lt;span class="n"&gt;foreign_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;-- SQLite&lt;/span&gt;

&lt;span class="c1"&gt;-- Disabling Foreign Keys in different databases&lt;/span&gt;
&lt;span class="n"&gt;PRAGMA&lt;/span&gt; &lt;span class="n"&gt;foreign_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;OFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;-- SQLite&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;FOREIGN_KEY_CHECKS&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="c1"&gt;-- MySQL&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                       &lt;span class="c1"&gt;-- PostgreSQL (after disabling it)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do &lt;strong&gt;exactly the same thing&lt;/strong&gt; in different databases, but it's not that common to find a tool that will translate it from a single source. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Translating SQL
&lt;/h2&gt;

&lt;p&gt;Imagine a tool that allows you to write a statement in SQL or even high order functions that are executed inside a database.&lt;/p&gt;

&lt;p&gt;This tool can also be used to generate the same query that will be executed, but for different relational databases and even in other paradigms like &lt;code&gt;Wide Column&lt;/code&gt; (ScyllaDB, CassandraDB).&lt;/p&gt;

&lt;p&gt;Did you visualized it? No? So let me present you the &lt;a href="https://github.com/SPLWare/esProc" rel="noopener noreferrer"&gt;esProc&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;esProc&lt;/strong&gt; is a powerful programming language that can work as a data warehouse, having many capabilities and one of them is to translate query statements to many different databases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;ADDDAYS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&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;ShipDate&lt;/span&gt;
&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqltranslate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MySQL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;DAY&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;ShipDate&lt;/span&gt;
&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqltranslate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Oracle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;NUMTODSINTERVAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;DAY&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;ShipDate&lt;/span&gt;
&lt;span class="k"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqltranslate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderDate&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;DAYS&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;ShipDate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a powerful and useful way to consume many database sources based in one unique language.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Final Considerations
&lt;/h2&gt;

&lt;p&gt;Having multiple databases inside a project would require tons of abstractions and implementations, however with a good tool.&lt;/p&gt;

&lt;p&gt;EsProc can bring you many possibilities to explore and I'll be inviting your to know more about them and star the repository on Github!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SPLWare/esProc" rel="noopener noreferrer"&gt;EsProc Github Link&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>esproc</category>
      <category>opensource</category>
      <category>sql</category>
    </item>
    <item>
      <title>I'm creating a new tech community</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Mon, 15 Jan 2024 15:01:52 +0000</pubDate>
      <link>https://forem.com/basementdevs/im-creating-a-new-tech-community-42mh</link>
      <guid>https://forem.com/basementdevs/im-creating-a-new-tech-community-42mh</guid>
      <description>&lt;p&gt;What's up folks! I'm here to recruit the coolest people to join my new community. &lt;/p&gt;

&lt;p&gt;Recently I decided to step down from my previous community, He4rt Developers (PT-BR) community and start a new thing focused in the international environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yet Another Tech Community
&lt;/h2&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%2F7uw0fdhxw7ebyk5toj8n.jpg" 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%2F7uw0fdhxw7ebyk5toj8n.jpg" alt="First Community Meeting" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;
&lt;p&gt;First weekly community meeting with a peak of 54 members&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;The community is called &lt;strong&gt;Basement Devs&lt;/strong&gt;, a community focused to help people to achieve better opportunities in Europe mostly (US can be a thing as well). &lt;/p&gt;

&lt;p&gt;Why I decided to start that: I want to give more people a &lt;strong&gt;safe place to practice English&lt;/strong&gt; and get better opportunities around the world through my network with the Microsoft MVP program, Developer Relations communities, and tech events I'm currently attending.&lt;/p&gt;

&lt;p&gt;I've been working with communities for 5 years so far, but this is the first time I've trying to make this a global thing, so it would be cool to have more people join us! &lt;/p&gt;

&lt;p&gt;So far the community has &lt;strong&gt;1,160 members&lt;/strong&gt; and 1 week of existence and most of the members are mid/senior level, Brazilians, from all possible backgrounds and stacks who &lt;strong&gt;want to mentor&lt;/strong&gt; a non-Portuguese speaker (any level) to practice their English. &lt;/p&gt;

&lt;p&gt;Also if you know anyone that wants to learn about programming, we'll be really glad to help them!&lt;/p&gt;

&lt;h2&gt;
  
  
  So what? Who can join us?
&lt;/h2&gt;

&lt;p&gt;If you're starting at programming or is already at the market and looking for guidance, our community is what you're looking for! &lt;/p&gt;

&lt;p&gt;We have members that works in huge companies like X-&lt;strong&gt;Team, Spotify and GitHub&lt;/strong&gt; (among many others) that will gladly &lt;strong&gt;help you when possible&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;And if you're in &lt;strong&gt;university&lt;/strong&gt;, it will also be a cool thing for you to share some of your problems and solutions for specific classes.&lt;/p&gt;

&lt;p&gt;The only thing that we ask you for is to respect the &lt;strong&gt;community rules&lt;/strong&gt; and the &lt;strong&gt;Discord guidelines&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps: stick together ft. Rust!
&lt;/h2&gt;

&lt;p&gt;Our focus is on the Discord community, and I also decided to use this fresh start to learn more about Rust. So all the tools/bots/whatever we're going to build there will use it.&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%2Fq6sbgaegdpo31lftfcd4.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%2Fq6sbgaegdpo31lftfcd4.png" alt="Weekly meeting schedule" width="589" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also I already scheduled a &lt;strong&gt;weekly growth meeting&lt;/strong&gt;, a very special moment to understand from the community what will be our next steps and also bring some good news! This meeting happens every Tuesday at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5PM (EST)&lt;/li&gt;
&lt;li&gt;7PM (BRT)&lt;/li&gt;
&lt;li&gt;11PM (CET)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... so feel free to join us if possible!&lt;/p&gt;

&lt;p&gt;Usually I do 6h at least of LiveCoding at Twitch and I'm getting at least 1h to discuss about the community together with the members, so, feel free to join us there as well!&lt;/p&gt;

&lt;p&gt;Anyway, thanks for reading this until now and welcome to our community!&lt;/p&gt;

&lt;p&gt;Link to &lt;a href="https://discord.gg/basementdevs" rel="noopener noreferrer"&gt;Discord Community&lt;/a&gt;&lt;br&gt;
Link to &lt;a href="https://twitch.tv/danielhe4rt" rel="noopener noreferrer"&gt;Twitch Channel&lt;/a&gt;&lt;br&gt;
Link to &lt;a href="https://twitter.com/danielhe4rt" rel="noopener noreferrer"&gt;Twitter Profile&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devrel</category>
      <category>community</category>
      <category>codenewbie</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Criando Exceptions para impressionar no Teste Técnico</title>
      <dc:creator>Daniel Reis</dc:creator>
      <pubDate>Tue, 10 Oct 2023 01:03:22 +0000</pubDate>
      <link>https://forem.com/he4rt/criando-exceptions-para-impressionar-no-teste-tecnico-2nie</link>
      <guid>https://forem.com/he4rt/criando-exceptions-para-impressionar-no-teste-tecnico-2nie</guid>
      <description>&lt;p&gt;Exceptions sempre vai ser um assunto constante quando o tópico for &lt;strong&gt;Orientação à Objetos&lt;/strong&gt; e hoje vamos descobrir como criá-las como um artesão de software!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tabela de Conteúdo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Prólogo&lt;/li&gt;
&lt;li&gt;2. O que gostariamos de EVITAR&lt;/li&gt;
&lt;li&gt;3. Refatoração 1: Criando Exceptions&lt;/li&gt;
&lt;li&gt;4. Design Patterns: Factory Pattern&lt;/li&gt;
&lt;li&gt;5. Refatoração 2: Refinando as Exceptions&lt;/li&gt;
&lt;li&gt;6. Conclusão&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Prólogo
&lt;/h2&gt;

&lt;p&gt;Quando eu comecei a estudar programação, um dos assuntos que sempre me assustava eram "erros" ou qualquer coisa que se relaciona à isso, porém após começar a estudar com mais frequencia, eu entendi que os erros e/ou &lt;strong&gt;Exceptions&lt;/strong&gt; são muito mais amigas do que inimigas. Mas é claro que pra isso, você precisa entender como utilizar de um jeito interessante pro seu projeto.&lt;/p&gt;

&lt;p&gt;No meu caso, acabava usando o trecho &lt;code&gt;throw new Exception()&lt;/code&gt; pra literalmente qualquer coisa e me perdia facilmente na codebase, por conta de uma Exception genérica espalhada no meio de tantas outras. No início não tinha problema, eu ainda não trabalhava com time que tinha observabilidade, então tá tudo certo.&lt;/p&gt;

&lt;p&gt;Passado o tempo, entrei em mais empresas FODAS e me deparei com excelentes implementações de Exceptions, principalmente o &lt;code&gt;Factory Pattern&lt;/code&gt;. Esse método me deixou maravilhado em como as coisas podem ser &lt;code&gt;simples e elegantes&lt;/code&gt;, mesmo quando se trata de erros.&lt;/p&gt;

&lt;p&gt;E hoje vou mostrar pra vocês como criar um certo &lt;strong&gt;gosto&lt;/strong&gt; em escrever exceções elegantes pra não encher seu código com 2km de mensagem de erro dentro da regra de negócio. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. O que gostariamos de EVITAR
&lt;/h2&gt;

&lt;p&gt;Vamos começar dando um pouco de contexto para esse tutorial: imagine que você tá desenvolvendo um sistema de RPG e nele você precisa criar um inventário simples pro seu personagem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src
├── Item
│   └── Item.php
└── Player
    ├── Inventory.php
    └── Player.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro desse contexto, imagine que você está tentando equipar um item no seu personagem. Porém, é lógico que nós vamos colocar algumas regras de validação com suas devidas &lt;code&gt;Exceptions&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DanielHe4rt\Player&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Item\Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Inventory&lt;/span&gt; &lt;span class="nv"&gt;$inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;equipItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s1"&gt;'Você não possui o item "'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'". '&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s1"&gt;'Você não pode equipar o item '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'pois o nível minimo é '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; 
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// faça coisas iradas&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;Vimos que existem duas regras de validação que jogam exceções diferentes pro nosso cliente. E pasmem: isso funciona (num cenário que o código tá completinho) e cumpre o papel de validação... MASSSSS, depois que eu aprendi que em testes de emprego o que é visto é a &lt;strong&gt;QUALIDADE DA ENTREGA&lt;/strong&gt; e não a agilidade que foi criado, meu mundo deu uma leve mudada para entender como transformar coisas que parecem "estranhas e feias" em coisas "simples e elegantes".&lt;/p&gt;

&lt;p&gt;Nesse caso, eu gostaria muito de evitar duas coisas: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exceptions genéricas;&lt;/li&gt;
&lt;li&gt;Exceptions que tomam conta de locais para regra de negócio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não entenda errado, as exceptions vão continuar onde elas estão, porém vamos melhorar a legibilidade do código.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Refatoração 1 : Criando Exceptions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src
├── Item
│   └── Item.php
└── Player
    ├── Exceptions
    │   ├── PlayerException.php
    │   └── PlayerInventoryException.php
    ├── Inventory.php
    └── Player.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beleza, agora passamos para parte que criamos nossa primeira &lt;code&gt;Exception&lt;/code&gt; "customizada", onde só estendemos a Exception base para uma nova classe. Não é nada de outro mundo, mas já melhora nossa legibilidade e entendimento do código em alguns vários pontos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DanielHe4rt\Player&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt;
&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E faremos uma refatoração simples na nossa função &lt;code&gt;equipItem()&lt;/code&gt;, reposicionando as exceptions padrões pela nova exception que criamos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DanielHe4rt\Player&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Item\Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Player\PlayerException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Player\PlayerInventoryException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Inventory&lt;/span&gt; &lt;span class="nv"&gt;$inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;equipItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s1"&gt;'Você não possui o item "'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'". '&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s1"&gt;'Você não pode equipar o item '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'pois o nível minimo é '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; 
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// faça coisas iradas&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;Com as novas Exceptions, agora sabemos exatamente do que se trata e principalmente onde buscar na nossa codebase quando essa Exception estourar.  É literalmente um &lt;code&gt;CTRL + ALT + F&lt;/code&gt; e pesquisar o nome &lt;strong&gt;"PlayerInventoryException"&lt;/strong&gt;. Facilita sua vida, a vida do DevOps que vai meter isso num NewRelic/DataDog da vida e assim seguimos. &lt;/p&gt;

&lt;p&gt;Porém algo ainda me incomoda muito... Por quê essas mensagens gigantes estão no meio da regra de negócio? Misturar pt-br com en desse jeito é triste d+ pra mim desculpa amigos!! Vamos aprender um jeito de por isso debaixo dos panos, porém antes precisamos passar num tópico de Design Pattern chamado Factory!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Design Patterns: Factory Pattern
&lt;/h2&gt;

&lt;p&gt;Se você já ouviu falar de &lt;strong&gt;Design Patterns&lt;/strong&gt;, provavelmente já entende um pouco sobre o que isso resolve. Mas caso não, eu te explico!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Design Patterns são soluções genéricas para problemas genéricos." - Alguém por ai&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nessa ideia de problemas genéricos, uma galera se reuniu e começou a criar alguns principios de Design de Software pra você resolver problemas do dia a dia com uma certa agilidade. Os Design Patterns são divididos em três tipos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Padrões Comportamentais;&lt;/li&gt;
&lt;li&gt;Padrões Criacionais;&lt;/li&gt;
&lt;li&gt;Padrões Estruturais.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;e você pode ler mais sobre eles no site &lt;a href="//https:/refactoring.guru"&gt;https:/refactoring.guru&lt;/a&gt; e eu recomendo MUITO pra qualquer pessoa desenvolvedora explorar essa documentação e se auto desenvolver. Ok, mas vamos focar nele, o tal do &lt;a href="https://refactoring.guru/pt-br/design-patterns/factory-method" rel="noopener noreferrer"&gt;Criacional de Fábrica (ou Factory Method)&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;A ideia desse padrão é você criar objetos sem ter que instaciar mil coisas em classes diferentes, você literalmente fabricar alguma instância de algo e só receber numa chamada simples de alguma função. No mundo da programação existem centenas de milhões de chamadas como &lt;code&gt;Models::make()&lt;/code&gt;, &lt;code&gt;Exception::create()&lt;/code&gt;, &lt;code&gt;ApiQualquer::factory()&lt;/code&gt; pra você não ter que acessar o método construtor de uma respectiva classe.&lt;/p&gt;

&lt;p&gt;Dando o exemplo de um Client de API, onde deixamos o construtor modular pra caso precisemos trocar a chave e segredo PORÉM ainda damos a possibilidade de uma chamada rápida fabricando o objeto final:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GithubClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'clientId'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'clientSecret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github.client_id'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'github.client_secret'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUserByUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'danielhe4rt'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// faça uma chamada pro github..&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Chamando sem fabricar o objeto&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GithubClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'client-id-foda'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'client-secret-foda'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUserByUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'danielhe4rt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Chamando usando o Factory &lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GithubClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getUserByUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'danielhe4rt'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nós fizemos uma chamada estática fabricando todos os parâmetros de um jeito sucinto. Esse "make/factory" ou o que você quiser chamar, pode ser um método bem extenso dependendo do que você for injetar mas isso não chega a ser problema.&lt;/p&gt;

&lt;p&gt;Mas de qualquer forma, vimos que a legibilidade usando o Factory Pattern foi melhorada, claro que você pode colocar melhores nomes pras funções mas na base é isso. Agora voltemos para nossas exceptions!&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Refatoração 2: Refinando as Exceptions
&lt;/h2&gt;

&lt;p&gt;Show, aprendemos um pouquinho sobre o factory, agora vamos aplicar. &lt;/p&gt;

&lt;p&gt;Criaremos um método de factory para nossa exception que faça sentido com o contexto do que tá acontecendo. Pois é, nada de usar "make" ou "create" nesses momentos. Exception precisam contar minimamente uma história pro usuário ou pro desenvolvedor do quê tá acontecendo e vamos focar nisso.&lt;/p&gt;

&lt;p&gt;Depois de uma leve refatoração na nossa &lt;code&gt;PlayerInventoryException&lt;/code&gt;, temos o resultado de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;itemNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$itemName&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Você não possui o item "%s".'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$itemName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt; &lt;span class="c1"&gt;// Forbidden&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E após chamarmos essa factory em nosso código, podemos perceber uma melhora de leitura e mantenibilidade já que isolamos as informações da Exception dentro da mesma.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;equipItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;itemNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'Você não pode equipar o item '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'pois o nível minimo é '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; 
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&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;Agora refatorando a próxima, temos a mesma ideia de trocar a PlayerException.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;lowLevelForThisEquipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$itemName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$itemLevel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'Você não pode equipar o item %s pois o nível minimo é %s.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$itemName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$itemLevel&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt; &lt;span class="c1"&gt;// Forbidden&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e agora nossa &lt;code&gt;equipItem()&lt;/code&gt; tá ó, uma maravilha!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;equipItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;itemNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;lowLevelForThisEquipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&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;Tá uma maravilha? Tá. Mas ainda tem algo me incomodando... Por quê passar os tipos primitivos sendo que essas exceptions estão se "comunicando" com classes?&lt;/p&gt;

&lt;p&gt;Ficaria bem mais limpo se passarmos a referência do objeto inteiro pra Exception e lá dentro ela resolve o que precisa usar. Afinal, vai que precisamos de mais algo num futuro e não custa nada já deixar bonitinho, né?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DanielHe4rt\Player&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Item\Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;lowLevelForThisEquipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'Você não pode equipar o item %s pois o nível minimo é %s.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt; &lt;span class="c1"&gt;// Forbidden&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;itemNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="nv"&gt;$message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Você não possui o item "%s".'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt; &lt;span class="c1"&gt;// Forbidden&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o resultado final do nosso método fica só o charme, tendo exceptions encapsuladas e ainda vai te gerar ótimos feedbacks na sua entrevista de emprego.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DanielHe4rt\Player&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Item\Item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Player\PlayerException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;DanielHe4rt\Player\PlayerInventoryException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Inventory&lt;/span&gt; &lt;span class="nv"&gt;$inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;equipItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;hasItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;PlayerInventoryException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;itemNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;minLevel&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;PlayerException&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;lowLevelForThisEquipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setupItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Item&lt;/span&gt; &lt;span class="nv"&gt;$item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// faça coisas iradas&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;h2&gt;
  
  
  6. Conclusão
&lt;/h2&gt;

&lt;p&gt;Exceptions são de longe uma das coisas mais "chatas" de se lidar. Afinal ninguém quer erro estourando na tela do cliente, mas no geral elas só precisam ter uma boa escrita e adicionar um pouquinho de charme com chamadas estáticas e &lt;strong&gt;PLAU&lt;/strong&gt; tu ganha um elogio e ponto positivo na entrevista de emprego.&lt;/p&gt;

&lt;p&gt;Espero que vocês tenham curtido o conteúdo e não esqueça de me seguir nas redes sociais!&lt;/p&gt;

&lt;p&gt;Referência: &lt;a href="https://www.rosstuck.com/formatting-exception-messages" rel="noopener noreferrer"&gt;Formatting Exception Messages&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oop</category>
      <category>php</category>
      <category>braziliandevs</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
