<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayrton Fidelis</title>
    <description>The latest articles on DEV Community by Ayrton Fidelis (@ayrtonvwf).</description>
    <link>https://dev.to/ayrtonvwf</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%2F107233%2Fe22ac586-f9cb-491e-a67c-35180d44ed4f.jpg</url>
      <title>DEV Community: Ayrton Fidelis</title>
      <link>https://dev.to/ayrtonvwf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ayrtonvwf"/>
    <language>en</language>
    <item>
      <title>The Great GraphQL Compass</title>
      <dc:creator>Ayrton Fidelis</dc:creator>
      <pubDate>Thu, 05 Jan 2023 18:38:46 +0000</pubDate>
      <link>https://dev.to/ayrtonvwf/the-great-graphql-compass-50f</link>
      <guid>https://dev.to/ayrtonvwf/the-great-graphql-compass-50f</guid>
      <description>&lt;p&gt;TLDR; Here's an organized collection of articles, guides and resources that you should be aware of when building GraphQL servers. Maybe hand the link to your team just in case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ayrtonvwf.gumroad.com/l/GraphQL-Apollo-Server-Must-Read"&gt;Here's the link (it's free)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does this exist?
&lt;/h2&gt;

&lt;p&gt;Have you ever shipped something and months later discovered some good piece of information that you wish you had early on, that would have saved you time, energy, money, that would make this thing you shipped more secure, reliable, pleasant to use?&lt;/p&gt;

&lt;p&gt;As I was navigating my way through GraphQL development over the past years I've been collecting and organizing the resources that explained important concepts that shaped the way I design and implement GraphQL.&lt;/p&gt;

&lt;p&gt;That's been a fundamental resource that I use when introducing GraphQL to individuals and teams and now I decided to share it here. Hope it helps you :)&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>learning</category>
      <category>guides</category>
      <category>articles</category>
    </item>
    <item>
      <title>Better results for product search on Elasticsearch</title>
      <dc:creator>Ayrton Fidelis</dc:creator>
      <pubDate>Tue, 13 Apr 2021 01:51:00 +0000</pubDate>
      <link>https://dev.to/ayrtonvwf/better-results-for-product-search-on-elasticsearch-1h09</link>
      <guid>https://dev.to/ayrtonvwf/better-results-for-product-search-on-elasticsearch-1h09</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;This week we managed to significantly improve the search feature in one of the platforms of our company with a tricky but simple technique that took some considerable research time, and because it was really hard to find references about how to implement it I decided to write about what I found and maybe help some random dev out there, so here we go:&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;First of all, we're talking about a "product search" feature. It happens by fetching products from a bunch of APIs and storing them in Elasticsearch to... you know... search.&lt;/p&gt;

&lt;p&gt;These APIs often provide too little data to be searched on. Descriptions are too vague and breaf, titles are often confuse, no categorization, but that's not explainable to our users. When a user searches for "laptops", they mostly want a laptop, not a book about laptops or even a toy laptop.&lt;/p&gt;

&lt;p&gt;That's where creativity entered into play.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patterns arise
&lt;/h2&gt;

&lt;p&gt;When brainstorming about ways to improve this product search, we whitnessed a pattern: the title of the products would most of the times start with it's name and follow with some characteristics and features, like in "Laptop Asus i7 8GB RAM", but the results that our users were getting included "Barbie Laptop" and "How to fix laptops - The definitive guide".&lt;/p&gt;

&lt;p&gt;The user looking to buy laptops would often search for "laptops" or include a combination of desired characteristics like "laptop 16GB i7", so we realized that our users would get more relevant products in the first results if we increased the score of results that matched the first word of the search term with the first word of the product title. That's what we did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Span First Query
&lt;/h2&gt;

&lt;p&gt;The right tool for this job would be the &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-first-query.html"&gt;Span First Query&lt;/a&gt;, which matches "spans" near the beginning of a field. This query expects an &lt;code&gt;end&lt;/code&gt; property that defines the number of terms in the beggining of the field to perform a query, and a &lt;code&gt;match&lt;/code&gt; property that defines another &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/span-queries.html"&gt;Span Query&lt;/a&gt; to be performed against these first terms.&lt;/p&gt;

&lt;p&gt;In this case we're looking to match terms, so we're using the &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-term-query.html"&gt;Span Term Query&lt;/a&gt;. Here's what our final query looks like:&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="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/products/_search&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;"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;"span_first"&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;"match"&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;"span_term"&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;"title"&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;"term"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptops"&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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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="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;But the often overlooked detail about the Span Term Query is that it compares the term that we provide with the normalized tokens of the field (like when you store the words "Dog" and "dogs" and Elasticsearch lowercases and de-pluralize them, more details in this &lt;a href="https://www.youtube.com/watch?v=7FLXjgB0PQI"&gt;amazing video that anyone ever touching Elasticsearch should watch&lt;/a&gt;), but the Span Term Query expects the term that we provide to be already normalized, so we should take a step back and take a look at the Analyze API in order to achieve this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normalizing the search term
&lt;/h2&gt;

&lt;p&gt;We need to turn the first word of our search string into a normalized token to be matched with the first term of the Span Query, and for that we use the &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.12/indices-analyze.html"&gt;Analyze API&lt;/a&gt;. We must be sure that the analyzer that's being used here is the same used when indexing the field that we'll be matching against. The easiest method to do that is to provide the name of the field to derive this setting from the field mapping.&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="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/products/_analyze&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;"field"&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="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&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="s2"&gt;"laptops"&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;The response of this request will contain information about the tokens:&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;"tokens"&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;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"start_offset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"end_offset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"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;"word"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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="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 this way we got out normalized token "laptop", which is what we must use in the Span Term Query. Remember this, it's important.&lt;/p&gt;

&lt;p&gt;Now we need to embed our Span First query into the query that we're using to search for products and increase ther score of the results that match with this new clause of the query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Span First Query to boost our previous results
&lt;/h2&gt;

&lt;p&gt;Here's a simplified version of our previous query, with a &lt;code&gt;must&lt;/code&gt; property saying that all of our results must include the search term in the title, and a &lt;code&gt;should&lt;/code&gt; property saying that results which include the search term in the description as well should have a higher score:&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="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/products/_search&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;"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;"bool"&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;"must"&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;"match"&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptops"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"should"&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;"match"&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;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptops"&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="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="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;To increase the score of results with matches on the first term, we'll put the span query on the should clause:&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="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/products/_search&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;"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;"bool"&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;"must"&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;"match"&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptops"&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="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"should"&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;"match"&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;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptops"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"span_first"&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;"match"&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;"span_term"&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;"title"&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;"term"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"laptop"&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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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="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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;The results are great.&lt;/p&gt;

&lt;p&gt;Our users now do find what they're looking for in the first products returned by our search feature. This change led to an increase in the value perception of our product and stakeholders are happy, but remember that this technique worked really well for the patterns detected in our data and our user's behavior, so do some investigation to see if it is the right solution for your use case.&lt;/p&gt;

&lt;p&gt;Cover image from &lt;a href="https://www.pexels.com/@olly"&gt;Andrea Piacquadio&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>elasticsearch</category>
      <category>lucene</category>
    </item>
    <item>
      <title>Best tip for GoLang programmers learning TypeScript</title>
      <dc:creator>Ayrton Fidelis</dc:creator>
      <pubDate>Thu, 25 Mar 2021 18:06:28 +0000</pubDate>
      <link>https://dev.to/ayrtonvwf/best-tip-for-golang-programmers-learning-typescript-1noa</link>
      <guid>https://dev.to/ayrtonvwf/best-tip-for-golang-programmers-learning-typescript-1noa</guid>
      <description>&lt;p&gt;I've been playing with GoLang recently, pretty cool language actually, but comming from a TypeScript world it was quite weird to me to use the &lt;code&gt;nil&lt;/code&gt; keyword instead of &lt;code&gt;null&lt;/code&gt;. I figured out that it could also be weird for Go devs learning TS, so here goes a little something to make the transition smoother:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nil&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that in place, Go devs are now able to use the familiar keyword instead of the longer alternative.&lt;/p&gt;

</description>
      <category>jokes</category>
      <category>go</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Building my personal website - Part 2 - The design</title>
      <dc:creator>Ayrton Fidelis</dc:creator>
      <pubDate>Wed, 11 Mar 2020 21:59:37 +0000</pubDate>
      <link>https://dev.to/ayrtonvwf/building-my-personal-website-part-2-the-design-4n43</link>
      <guid>https://dev.to/ayrtonvwf/building-my-personal-website-part-2-the-design-4n43</guid>
      <description>&lt;p&gt;Oh boy, here comes a tricky one.&lt;/p&gt;

&lt;p&gt;As stated on the previous article, I've looked for content guidance, but proactively avoided any design inspiration. Even though I'm not a designer, I wanted to make this website as mine as possible.&lt;/p&gt;

&lt;p&gt;Performance was a concern from the very beginning: I avoided using images as much as I could and used a pretty common font-face from Google Fonts, so that most users would have it cached already. You guessed it. It's Roboto.&lt;/p&gt;

&lt;p&gt;The first thing I designed was a logo. I didn't know at that time, but it showed crucial on shaping the website as a whole. The final logo turned into something really simple: a colorful version of the website's domain.&lt;/p&gt;

&lt;p&gt;Now we've got to a delicate point.&lt;/p&gt;

&lt;h1&gt;
  
  
  What the domain??!?#!%*?
&lt;/h1&gt;

&lt;p&gt;Ok, I'll say it out loud: ayrtonvwf.dev.&lt;/p&gt;

&lt;p&gt;Ask your mom to go to this website and watch her never being able to type it correctly.&lt;/p&gt;

&lt;p&gt;The .dev part is pretty obvious, although non-dev folks would have a hard time believing that they've got it right.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What? .dev? Is that a thing?"&lt;br&gt;
– Non-dev person.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've heard it a lot already, and it's not even deployed.&lt;/p&gt;

&lt;p&gt;ayrtonvwf? My name concatenated to my initials. I've used it as a username on every social network since I started interneting. Easy &lt;strong&gt;for me&lt;/strong&gt; to remember and it won't ever be taken by someone else before me, but it's a nightmare for other people to remember and that's a serious accessibility issue.&lt;/p&gt;

&lt;p&gt;But, at the end of the day, I feel that it's uniqueness is what makes it work. It stands out. Most of the people will only click on a link rather than typing it, so I guess it's not a total disaster.&lt;/p&gt;

&lt;p&gt;It's a bad decision that I don't regret.&lt;/p&gt;

&lt;p&gt;Mostly important: I've chosen it in less than a week.&lt;/p&gt;

&lt;h1&gt;
  
  
  Don't start with a big bitmap image so that the first impression of the site will load instantly
&lt;/h1&gt;

&lt;p&gt;That was my first challenge when I opened &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt; to start the design. I've failed.&lt;/p&gt;

&lt;p&gt;The user should understand right away that this website is about a person, a developer, rather than an enterprise or a single product. It felt so personal with a picture of an actual human being that I couldn't come back.&lt;/p&gt;

&lt;h1&gt;
  
  
  It feels like many websites glued together
&lt;/h1&gt;

&lt;p&gt;It does.&lt;/p&gt;

&lt;p&gt;The layout consists of the following sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Me&lt;/li&gt;
&lt;li&gt;Personal Project 1&lt;/li&gt;
&lt;li&gt;Personal Project 2&lt;/li&gt;
&lt;li&gt;Contact info&lt;/li&gt;
&lt;li&gt;Footnotes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each Personal Project section feels like a separated website embedded into the main one. The first project is about security, so it feels bold and strong. The second one is about a lightweight layout, so it feels light and minimal.&lt;/p&gt;

&lt;p&gt;In both cases, it's not &lt;strong&gt;me&lt;/strong&gt;, a developer, talking about a product. It's the product presenting itself to the newcomer, with it's own personality and focusing on it's own features.&lt;/p&gt;

&lt;p&gt;Building these so-different sections into my website is an arguable decision that I'm proud of making in less than a week.&lt;/p&gt;

&lt;p&gt;It works.&lt;/p&gt;

&lt;h1&gt;
  
  
  The final design
&lt;/h1&gt;

&lt;p&gt;It's finished.&lt;/p&gt;

&lt;p&gt;I'll surely change some margins and font sizes as needed while implementing it, but it's finished. In less than a week.&lt;/p&gt;

&lt;p&gt;One of my biggest challenges was &lt;strong&gt;not&lt;/strong&gt; spending a whole month on every detail. I'm trying to finish a step and move to the next one before I get caught into a never ending loop. It's working.&lt;/p&gt;

&lt;p&gt;Next step: Implementing a static website with no JS (and refusing to make it less of an website because of that).&lt;/p&gt;

</description>
      <category>design</category>
      <category>webdev</category>
      <category>portfolio</category>
      <category>ux</category>
    </item>
    <item>
      <title>Building my personal website - Part 1 - The content</title>
      <dc:creator>Ayrton Fidelis</dc:creator>
      <pubDate>Fri, 21 Feb 2020 11:47:20 +0000</pubDate>
      <link>https://dev.to/ayrtonvwf/building-my-personal-website-part-1-the-content-3f5b</link>
      <guid>https://dev.to/ayrtonvwf/building-my-personal-website-part-1-the-content-3f5b</guid>
      <description>&lt;p&gt;After I gave my first public tech talk, I finally felt confident enough to expose myself to the international dev community. And as I've just shut down two personal projects that were taking up my free time, I decided that time has come: I would build my personal website.&lt;/p&gt;

&lt;p&gt;The first thing I did was look for articles about what a personal website should be like, specifically what content should it include. It was a good first step to the wrong direction.&lt;/p&gt;

&lt;h1&gt;
  
  
  A good first step to the wrong direction.
&lt;/h1&gt;

&lt;p&gt;I avoided looking for design inspiration and focused on the content instead. After a bit of research I came up with a list.&lt;/p&gt;

&lt;p&gt;A personal website must have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to find contact info&lt;/li&gt;
&lt;li&gt;Downloadable Curriculum Vitae&lt;/li&gt;
&lt;li&gt;A list of my strongest skills&lt;/li&gt;
&lt;li&gt;My best personal projects&lt;/li&gt;
&lt;li&gt;My personality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started to prototype it, completely ignoring the list I've just made. With the first proposal finished I realized it had nothing to do with these items.&lt;/p&gt;

&lt;p&gt;The fact is: that was somebody else's list. It includes what's important to other people who have already built their websites and written articles about it.&lt;/p&gt;

&lt;p&gt;Realizing this I started to think about what &lt;strong&gt;my&lt;/strong&gt; site should be. It must be a professional dev website, describing me and what I do, featuring some personal projects and my dev contact info.&lt;/p&gt;

&lt;p&gt;I dropped the Curriculum Vitae: it should be personalized to a specific job position, featuring only relevant information.&lt;/p&gt;

&lt;p&gt;The skills list? It just doesn't feel right to choose somethings and leaving others off of the plate. Should I put how much % of PHP I know? Should I separate Typescript from JS and SASS from CSS? Why bother? I decided that giving only the general context that I'm (mostly) a web developer would be the right thing to do.&lt;/p&gt;

&lt;p&gt;Having the content in mind, I defined what's important to me on a good website in general. It should be fast, accessible, respecting the user preferences (dark mode, low motion, zoom) and should be simple. It must be totally static to be served by GitHub Pages.&lt;/p&gt;

&lt;p&gt;It should have no JS. Ok, this last one is just a whim of mine.&lt;/p&gt;

&lt;p&gt;Ancient browser support is not something that I'll be worried about. My public target (people interested in web development) is known for hating those entities.&lt;/p&gt;

&lt;p&gt;Now that I knew what my site should be, it was time to start the design.&lt;/p&gt;

&lt;p&gt;Spoiler: I'm not a designer.&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>webdev</category>
      <category>design</category>
    </item>
    <item>
      <title>A useful progress-bar fallback to IE9. CSS-only.</title>
      <dc:creator>Ayrton Fidelis</dc:creator>
      <pubDate>Tue, 16 Oct 2018 00:05:13 +0000</pubDate>
      <link>https://dev.to/ayrtonvwf/a-useful-progress-bar-fallback-to-ie9-css-only-14o0</link>
      <guid>https://dev.to/ayrtonvwf/a-useful-progress-bar-fallback-to-ie9-css-only-14o0</guid>
      <description>&lt;p&gt;Progress bars are tricky elements to be styled.&lt;/p&gt;

&lt;p&gt;Yes, it's completely possible to make them look nice cross-browser with only CSS as &lt;a href="https://css-tricks.com/html5-progress-element"&gt;this CSS-TRICKS post&lt;/a&gt; shows us. But making them look nice is not the point of this article.&lt;/p&gt;

&lt;p&gt;The point of this article is making them useful for browsers that don't understand the &lt;code&gt;progress&lt;/code&gt; element by themselves, and can't render that visible progress bar.&lt;/p&gt;

&lt;p&gt;And it's simple.&lt;/p&gt;

&lt;p&gt;Let's take a look at a basic &lt;code&gt;progress&lt;/code&gt; markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;progress&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"15"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/progress&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To a browser that don't understand what &lt;code&gt;progress&lt;/code&gt; means, it's just a &lt;a href="https://html.spec.whatwg.org/multipage/dom.html#htmlunknownelement"&gt;HTMLUnknownElement&lt;/a&gt; with the properties &lt;code&gt;min="0" max="100" value="15"&lt;/code&gt;. What can we do with that?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;:before&lt;/code&gt; and &lt;code&gt;:after&lt;/code&gt; to inject the text &lt;em&gt;15/100&lt;/em&gt; inside it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* make it look like a box */&lt;/span&gt;
&lt;span class="nt"&gt;progress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="c"&gt;/* make pseudo-elements 50% side-by-side */&lt;/span&gt;
&lt;span class="nt"&gt;progress&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;progress&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* put the value and a slash on the left half, aligned to the right */&lt;/span&gt;
&lt;span class="nt"&gt;progress&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&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="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* put the max value on the right half */&lt;/span&gt;
&lt;span class="nt"&gt;progress&lt;/span&gt;&lt;span class="nd"&gt;:after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max&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;ul&gt;
&lt;li&gt;If we're sure that our progress elements will have a maximum of 100, we can show it with the &lt;code&gt;%&lt;/code&gt; instead:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* make it look like a box */&lt;/span&gt;
&lt;span class="nt"&gt;progress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* put the value and the percent sign in the middle of the pseudo-element */&lt;/span&gt;
&lt;span class="nt"&gt;progress&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&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="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&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;Here's a simple demo of the two situations working (with &lt;code&gt;div&lt;/code&gt; instead of &lt;code&gt;progress&lt;/code&gt;):&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/ayrtonvwf/embed/yRPGWm?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Here's this concept applied to that nice fully-styled progress-bar from &lt;a href="https://css-tricks.com/html5-progress-element"&gt;that CSS-TRICKS post&lt;/a&gt;.&lt;br&gt;
&lt;iframe height="600" src="https://codepen.io/ayrtonvwf/embed/JZWENR?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>ie9</category>
    </item>
  </channel>
</rss>
