<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2024-05-05T20:28:50+00:00</updated><id>/feed.xml</id><title type="html">Nicolás J. Engler - Articles &amp;amp; Posts Repository</title><subtitle>This is a repository dedicated to posts and articles I've written in the past, spread throughout the web, either on sites like CodePen or as an invited author.
</subtitle><entry><title type="html">Embracing the potential of generalist profiles in tech</title><link href="/insight/2024/05/05/embracing-potential-generalists.html" rel="alternate" type="text/html" title="Embracing the potential of generalist profiles in tech" /><published>2024-05-05T04:00:00+00:00</published><updated>2024-05-05T04:00:00+00:00</updated><id>/insight/2024/05/05/embracing-potential-generalists</id><content type="html" xml:base="/insight/2024/05/05/embracing-potential-generalists.html"><![CDATA[<p>🚀 Embracing the Potential of Generalist Profiles in Tech 🚀</p>

<p>In a world often fixated on specialization, let’s shine a light on the invaluable contributions of generalist profiles. Here’s why their versatility is a force to be reckoned with:</p>

<p>🎯 Navigating the Hiring Landscape: Amidst recruitment processes favoring deep expertise in specific technologies, let’s not overlook the unique skill set that generalists bring to the table. While specialization has its merits, the ability to handle a wide array of tasks is a hallmark of generalist profiles. They excel in adapting to diverse challenges and bringing fresh perspectives to the team dynamic.</p>

<p>💡 From Concept to Completion: Generalists are the unsung heroes of product creation. Their ability to navigate the initial stages of a project, from ideation to execution, is unparalleled. Whether it’s brainstorming ideas, managing processes, or troubleshooting, generalists are equipped to handle it all. Their versatility also makes them invaluable assets in freelance opportunities, where the ability to manage projects from beginning to end is paramount (especially on smaller budgets!).</p>

<p>🤝 Collaboration Across Disciplines: Generalists thrive in the intersectionality of teams. Their ability to collaborate with individuals from diverse backgrounds, including marketing, design, development, and management, is crucial for fostering innovation and most of the times driving projects forward. They serve as the bridge between different departments oftentimes pushing the roadmap forward, seamlessly integrating ideas and perspectives to create cohesive and impactful solutions.</p>

<p>🤖 Adapting to AI in the Workplace: As AI continues to reshape the workplace, it’s natural to wonder about its impact on the role of generalists. While AI undoubtedly automates certain tasks and processes, the question arises: Could AI eventually replace generalists to some extent, pushing the world towards greater specialization?</p>

<p>The rise of AI raises valid concerns about the future of work and the need for specialized skills in certain domains. However, the adaptability and versatility inherent in generalist profiles offer a unique advantage. Generalists possess a diverse skill set that enables them to pivot and evolve alongside AI technologies. Rather than viewing AI as a threat, generalists can leverage its capabilities to enhance their problem-solving abilities and drive innovation.</p>

<p>While some tasks may become automated, the human element of creativity, critical thinking, and cross-disciplinary collaboration remains invaluable. Generalists excel in navigating complex, interdisciplinary challenges, bridging gaps between different domains and driving holistic solutions.</p>

<p>As we embrace the potential of AI in the workplace, the role of generalists may evolve, but their importance will endure. The key lies in recognizing the symbiotic relationship between AI and human ingenuity, harnessing technology to augment rather than replace the unique skills and perspectives that generalists bring to the table.</p>

<p>🌐 Tech Awareness: In today’s fast-paced tech landscape, staying informed is more critical than ever. Generalists possess a holistic understanding of the broader tech ecosystem, allowing them to anticipate trends, identify opportunities, and adapt to evolving industry dynamics. Their ability to connect the dots across different domains enables them to innovate and drive meaningful change.</p>

<p>Let’s celebrate the power of generalist profiles and recognize the unique contributions they bring to the tech world. Embracing diversity in skill sets fosters innovation, collaboration, and ultimately, success. Are you a generalist making waves in tech? I’d love to hear your thoughts and experiences in the comments below! #GeneralistPower #TechInnovation #EmbraceVersatility</p>]]></content><author><name></name></author><category term="insight" /><summary type="html"><![CDATA[🚀 Embracing the Potential of Generalist Profiles in Tech 🚀]]></summary></entry><entry><title type="html">Summarizing your Gmail inbox newsletters using OpenAI</title><link href="/insight/2024/01/04/openai-api-email-summarize.html" rel="alternate" type="text/html" title="Summarizing your Gmail inbox newsletters using OpenAI" /><published>2024-01-04T04:00:00+00:00</published><updated>2024-01-04T04:00:00+00:00</updated><id>/insight/2024/01/04/openai-api-email-summarize</id><content type="html" xml:base="/insight/2024/01/04/openai-api-email-summarize.html"><![CDATA[<p>As I’ve written on a <a href="https://www.linkedin.com/posts/nicolasjengler_ai-informationoptimization-professionalefficiency-activity-7148654214834020352-CapQ">LinkedIn post</a>, lately I’ve been using OpenAI’s ChatGPT to summarize some blog posts and most of the newsletters I receive on my main email address. It has been a great experience as it allows me to efficiently consume the main discussion. I can also expand or dive deeper if it interests me enough.</p>

<p>I decided to try and automate the process as much as possible and created this proof-of-concept that attempts to retrieve emails from your Gmail inbox and summarize them using OpenAI’s API. DISCLAIMER: The script is written in Python and uses pip to manage dependencies. However, I’m almost certain it can be adapted to a JavaScript/Node-based environment if needed.</p>

<hr />

<p>To create a command-line application that fetches emails from Gmail and summarizes them using OpenAI’s API, you’ll need to follow the following steps. We’ll be using the <code class="language-plaintext highlighter-rouge">google-auth</code> library for Gmail authentication and the <code class="language-plaintext highlighter-rouge">openai</code> library for ChatGPT API access. Please note that you’ll need to install these libraries first using <code class="language-plaintext highlighter-rouge">pip</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>google-auth google-auth-oauthlib google-auth-httplib2 openai
</code></pre></div></div>

<p>Now, let’s create a basic script. Ensure you have the required API keys and credentials for Gmail and OpenAI.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">openai</span>
<span class="kn">from</span> <span class="nn">google.oauth2.credentials</span> <span class="kn">import</span> <span class="n">Credentials</span>
<span class="kn">from</span> <span class="nn">google_auth_oauthlib.flow</span> <span class="kn">import</span> <span class="n">InstalledAppFlow</span>
<span class="kn">from</span> <span class="nn">google.auth.transport.requests</span> <span class="kn">import</span> <span class="n">Request</span>
<span class="kn">import</span> <span class="nn">googleapiclient.discovery</span>

<span class="c1"># Set up Google API credentials, these will be stored as JSON files that for simplicity's sake will live in the root directory of the project
</span><span class="n">SCOPES</span> <span class="o">=</span> <span class="p">[</span><span class="s">'https://www.googleapis.com/auth/gmail.readonly'</span><span class="p">]</span>
<span class="n">API_TOKEN_PATH</span> <span class="o">=</span> <span class="s">'token.json'</span>
<span class="n">CREDENTIALS_PATH</span> <span class="o">=</span> <span class="s">'credentials.json'</span>

<span class="c1"># OpenAI
</span><span class="n">OPENAI_API_KEY</span> <span class="o">=</span> <span class="s">'YOUR_OPENAI_API_KEY'</span>

<span class="k">def</span> <span class="nf">authenticate_gmail</span><span class="p">():</span>
    <span class="n">creds</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">exists</span><span class="p">(</span><span class="n">API_TOKEN_PATH</span><span class="p">):</span>
        <span class="n">creds</span> <span class="o">=</span> <span class="n">Credentials</span><span class="p">.</span><span class="n">from_authorized_user_file</span><span class="p">(</span><span class="n">API_TOKEN_PATH</span><span class="p">)</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">creds</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">creds</span><span class="p">.</span><span class="n">valid</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">creds</span> <span class="ow">and</span> <span class="n">creds</span><span class="p">.</span><span class="n">expired</span> <span class="ow">and</span> <span class="n">creds</span><span class="p">.</span><span class="n">refresh_token</span><span class="p">:</span>
            <span class="n">creds</span><span class="p">.</span><span class="n">refresh</span><span class="p">(</span><span class="n">Request</span><span class="p">())</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">flow</span> <span class="o">=</span> <span class="n">InstalledAppFlow</span><span class="p">.</span><span class="n">from_client_secrets_file</span><span class="p">(</span><span class="n">CREDENTIALS_PATH</span><span class="p">,</span> <span class="n">SCOPES</span><span class="p">)</span>
            <span class="n">creds</span> <span class="o">=</span> <span class="n">flow</span><span class="p">.</span><span class="n">run_local_server</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>

        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">API_TOKEN_PATH</span><span class="p">,</span> <span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">token</span><span class="p">:</span>
            <span class="n">token</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">creds</span><span class="p">.</span><span class="n">to_json</span><span class="p">())</span>

    <span class="k">return</span> <span class="n">creds</span>

<span class="k">def</span> <span class="nf">get_emails</span><span class="p">():</span>
    <span class="n">creds</span> <span class="o">=</span> <span class="n">authenticate_gmail</span><span class="p">()</span>
    <span class="n">service</span> <span class="o">=</span> <span class="n">googleapiclient</span><span class="p">.</span><span class="n">discovery</span><span class="p">.</span><span class="n">build</span><span class="p">(</span><span class="s">'gmail'</span><span class="p">,</span> <span class="s">'v1'</span><span class="p">,</span> <span class="n">credentials</span><span class="o">=</span><span class="n">creds</span><span class="p">)</span>

    <span class="n">results</span> <span class="o">=</span> <span class="n">service</span><span class="p">.</span><span class="n">users</span><span class="p">().</span><span class="n">messages</span><span class="p">().</span><span class="nb">list</span><span class="p">(</span><span class="n">userId</span><span class="o">=</span><span class="s">'me'</span><span class="p">,</span> <span class="n">labelIds</span><span class="o">=</span><span class="p">[</span><span class="s">'INBOX'</span><span class="p">]).</span><span class="n">execute</span><span class="p">()</span>
    <span class="n">messages</span> <span class="o">=</span> <span class="n">results</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'messages'</span><span class="p">,</span> <span class="p">[])</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">messages</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'No messages found.'</span><span class="p">)</span>
        <span class="k">return</span> <span class="p">[]</span>

    <span class="k">return</span> <span class="n">messages</span>

<span class="k">def</span> <span class="nf">summarize_email</span><span class="p">(</span><span class="n">email_body</span><span class="p">):</span>
    <span class="n">openai</span><span class="p">.</span><span class="n">api_key</span> <span class="o">=</span> <span class="n">OPENAI_API_KEY</span>
    
    <span class="n">prompt</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"Please, summarize the following newsletter:</span><span class="se">\n</span><span class="si">{</span><span class="n">email_body</span><span class="si">}</span><span class="s">"</span>
    
    <span class="c1"># Adjust your OpenAI settings when processing content here
</span>    <span class="c1"># These are settings specific to OpenAI so check their docs if you want further clarity
</span>    <span class="n">response</span> <span class="o">=</span> <span class="n">openai</span><span class="p">.</span><span class="n">Completion</span><span class="p">.</span><span class="n">create</span><span class="p">(</span>
        <span class="n">engine</span><span class="o">=</span><span class="s">"text-davinci-003"</span><span class="p">,</span>
        <span class="n">prompt</span><span class="o">=</span><span class="n">prompt</span><span class="p">,</span>
        <span class="n">max_tokens</span><span class="o">=</span><span class="mi">150</span><span class="p">,</span>
        <span class="n">temperature</span><span class="o">=</span><span class="mf">0.7</span>
    <span class="p">)</span>

    <span class="k">return</span> <span class="n">response</span><span class="p">.</span><span class="n">choices</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">emails</span> <span class="o">=</span> <span class="n">get_emails</span><span class="p">()</span>

    <span class="k">for</span> <span class="n">email</span> <span class="ow">in</span> <span class="n">emails</span><span class="p">:</span>
        <span class="n">message</span> <span class="o">=</span> <span class="n">service</span><span class="p">.</span><span class="n">users</span><span class="p">().</span><span class="n">messages</span><span class="p">().</span><span class="n">get</span><span class="p">(</span><span class="n">userId</span><span class="o">=</span><span class="s">'me'</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="n">email</span><span class="p">[</span><span class="s">'id'</span><span class="p">]).</span><span class="n">execute</span><span class="p">()</span>
        <span class="n">email_body</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s">'snippet'</span><span class="p">]</span>  <span class="c1"># You may need to adjust this based on the email structure
</span>
        <span class="n">summary</span> <span class="o">=</span> <span class="n">summarize_email</span><span class="p">(</span><span class="n">email_body</span><span class="p">)</span>
        <span class="c1"># Uncomment the following line if you want the full original email to show right before getting the summary
</span>        <span class="c1"># print(f"Original Email:\n{email_body}\n")
</span>        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Summarized Email:</span><span class="se">\n</span><span class="si">{</span><span class="n">summary</span><span class="si">}</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"="</span><span class="o">*</span><span class="mi">50</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</code></pre></div></div>

<p>Obviously feel free to adjust the code according to your specific use case, especially when handling email bodies and formatting (this can prove tricky as formats can vary wildly, I’ve noticed this to be more efficient with LinkedIn community newsletters).</p>

<p>I hope you put this weird little experiment to good use!</p>]]></content><author><name></name></author><category term="insight" /><summary type="html"><![CDATA[As I’ve written on a LinkedIn post, lately I’ve been using OpenAI’s ChatGPT to summarize some blog posts and most of the newsletters I receive on my main email address. It has been a great experience as it allows me to efficiently consume the main discussion. I can also expand or dive deeper if it interests me enough.]]></summary></entry><entry><title type="html">Creating a custom RSS feed for sites that don’t have one</title><link href="/fun/2023/10/18/goodreads-custom-rss-feed.html" rel="alternate" type="text/html" title="Creating a custom RSS feed for sites that don’t have one" /><published>2023-10-18T04:00:00+00:00</published><updated>2023-10-18T04:00:00+00:00</updated><id>/fun/2023/10/18/goodreads-custom-rss-feed</id><content type="html" xml:base="/fun/2023/10/18/goodreads-custom-rss-feed.html"><![CDATA[<p>One of my 2023 resolutions was to get back into the habit of reading, especially since I decided to stop being a snob and read whatever I truly wanted (even if that was some questionable fanfic-y literature). My go-to website to track the books I delve into is <a href="https://goodreads.com">Goodreads</a>. Goodreads has an amazing “news” section that’s essentially a blog where they recommend upcoming books and I usually align pretty well with what they promote over there, but the sad news is that they don’t offer an RSS feed for their news section.</p>

<p>Ever since I left (most) social media, a lot of the information I consume is through RSS feeds (thanks <a href="https://netnewswire.com/">NetNewsWire</a>), so this was an issue. Yes, I could’ve signed up for email notifications but in all reality I wanted to have all the content centralized in my reader, so that’s when I took it into my own hands to offer myself a way to create a custom RSS feed.</p>

<h3 id="prerequisites">Prerequisites</h3>

<p>Before we start, make sure you have Node.js installed on your machine. If not, you can download it from <a href="https://nodejs.org/">Node.js’ website</a>.</p>

<h2 id="step-1-set-up-the-project">Step 1: Set Up the Project</h2>

<p>Create a new Node.js project and install the dependencies we’ll be using.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>goodreads-rss-feed
<span class="nb">cd </span>goodreads-rss-feed
npm init <span class="nt">-y</span>
npm <span class="nb">install </span>express request cheerio rss fs path
</code></pre></div></div>

<h2 id="step-2-write-an-express-app">Step 2: Write an Express App</h2>

<p>Write an Express App to expose an API endpoint to serve the XML output. Create a file named <code class="language-plaintext highlighter-rouge">app.js</code> and add the initial setup for your Express application.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">request</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">cheerio</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">cheerio</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">RSS</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">rss</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">fs</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">path</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">path</span><span class="dl">'</span><span class="p">);</span>

<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">port</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">PORT</span> <span class="o">||</span> <span class="mi">3000</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="step-3-function-to-create-rss-feed">Step 3: Function to Create RSS Feed</h2>

<p>Define a function <code class="language-plaintext highlighter-rouge">createRSSFeed</code> that will create the RSS feed by scraping Goodreads content. <strong>IMPORTANT</strong>: this approach could be used for virtually any website that has a sort-of defined HTML structure to offer a list of latest blog posts.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">createRSSFeed</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="nx">feedTitle</span><span class="p">,</span> <span class="nx">feedDescription</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">request</span><span class="p">(</span><span class="nx">url</span><span class="p">,</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">response</span><span class="p">,</span> <span class="nx">html</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="k">if</span> <span class="p">(</span><span class="nx">error</span> <span class="o">||</span> <span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">!==</span> <span class="mi">200</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">reject</span><span class="p">(</span><span class="nx">error</span> <span class="o">||</span> <span class="s2">`Request failed with status code </span><span class="p">${</span><span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
      <span class="p">}</span>

      <span class="kd">const</span> <span class="nx">$</span> <span class="o">=</span> <span class="nx">cheerio</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">html</span><span class="p">);</span>
      <span class="kd">const</span> <span class="nx">feed</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">RSS</span><span class="p">({</span>
        <span class="na">title</span><span class="p">:</span> <span class="nx">feedTitle</span><span class="p">,</span>
        <span class="na">description</span><span class="p">:</span> <span class="nx">feedDescription</span><span class="p">,</span>
        <span class="na">feed_url</span><span class="p">:</span> <span class="s2">`</span><span class="p">${</span><span class="nx">url</span><span class="p">}</span><span class="s2">/rss.xml`</span><span class="p">,</span>
        <span class="na">site_url</span><span class="p">:</span> <span class="nx">url</span><span class="p">,</span>
      <span class="p">});</span>

      <span class="c1">// This chunk of code is based on Goodreads current HTML structure to show their latest blog posts</span>
      <span class="c1">// If you're using this for a different website, you'll need to inspect their markup and adjust this accordingly</span>
      <span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.editorialCard</span><span class="dl">'</span><span class="p">).</span><span class="nx">each</span><span class="p">((</span><span class="nx">index</span><span class="p">,</span> <span class="nx">element</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">title</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">element</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="dl">'</span><span class="s1">.editorialCard__title</span><span class="dl">'</span><span class="p">).</span><span class="nx">text</span><span class="p">();</span>
        <span class="kd">const</span> <span class="nx">link</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">element</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="dl">'</span><span class="s1">.editorialCard__title .gr-hyperlink</span><span class="dl">'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="dl">'</span><span class="s1">href</span><span class="dl">'</span><span class="p">);</span>
        <span class="kd">const</span> <span class="nx">description</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">element</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="dl">'</span><span class="s1">.editorialCard__body</span><span class="dl">'</span><span class="p">).</span><span class="nx">text</span><span class="p">();</span>
        <span class="kd">const</span> <span class="nx">pubDate</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">element</span><span class="p">).</span><span class="nx">find</span><span class="p">(</span><span class="dl">'</span><span class="s1">.editorialCard__timestamp</span><span class="dl">'</span><span class="p">).</span><span class="nx">text</span><span class="p">();</span>

        <span class="nx">feed</span><span class="p">.</span><span class="nx">item</span><span class="p">({</span>
          <span class="na">title</span><span class="p">:</span> <span class="nx">title</span><span class="p">,</span>
          <span class="na">description</span><span class="p">:</span> <span class="nx">description</span><span class="p">,</span>
          <span class="na">url</span><span class="p">:</span> <span class="nx">link</span><span class="p">,</span>
          <span class="na">date</span><span class="p">:</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">pubDate</span><span class="p">),</span>
        <span class="p">});</span>
      <span class="p">});</span>
      
      <span class="kd">const</span> <span class="nx">xml</span> <span class="o">=</span> <span class="nx">feed</span><span class="p">.</span><span class="nx">xml</span><span class="p">({</span> <span class="na">indent</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span>
      <span class="nx">resolve</span><span class="p">(</span><span class="nx">xml</span><span class="p">);</span>
    <span class="p">});</span>
  <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="step-4-express-route-for-rss-feed">Step 4: Express Route for RSS Feed</h2>

<p>Define an Express route <code class="language-plaintext highlighter-rouge">/api/rss</code> that triggers the creation of the RSS feed when accessed and serves an XML output for your reader of choice to feed upon. <strong>IMPORTANT</strong>: I decided to use Vercel to host this API, which is why my route is preceded by <code class="language-plaintext highlighter-rouge">/api</code>, but this isn’t mandatory and could be adjusted based on how you’ll be hosting the application.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/api/rss</span><span class="dl">'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="k">try</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">feed</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">createRSSFeed</span><span class="p">(</span>
      <span class="dl">'</span><span class="s1">https://www.goodreads.com/news</span><span class="dl">'</span><span class="p">,</span>
      <span class="dl">'</span><span class="s1">Goodreads RSS Feed</span><span class="dl">'</span><span class="p">,</span>
      <span class="dl">'</span><span class="s1">Latest articles from Goodreads</span><span class="dl">'</span>
    <span class="p">);</span>

    <span class="nx">res</span><span class="p">.</span><span class="nx">header</span><span class="p">(</span><span class="dl">'</span><span class="s1">Content-Type</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">application/xml</span><span class="dl">'</span><span class="p">);</span>
    <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">feed</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Error generating or sending RSS feed:</span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
    <span class="nx">res</span><span class="p">.</span><span class="nx">status</span><span class="p">(</span><span class="mi">500</span><span class="p">).</span><span class="nx">send</span><span class="p">(</span><span class="dl">'</span><span class="s1">Internal Server Error</span><span class="dl">'</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>

<h2 id="step-5-start-the-server">Step 5: Start the Server</h2>

<p>Start the Express server to make your RSS feed accessible.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`Server is running on port </span><span class="p">${</span><span class="nx">port</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">});</span>

<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">app</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="step-6-run-the-application">Step 6: Run the Application</h2>

<p>Run your application using the following command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node app.js
</code></pre></div></div>

<p><strong>IMPORTANT</strong>: for persistence, you could host this in a service such as Heroku or Vercel, rather than depending on the host machine running the application for availability.</p>

<p>Visit <a href="http://localhost:3000/api/rss">http://localhost:3000/api/rss</a> in your browser to access the custom Goodreads RSS feed.</p>

<p>That’s it! You’ve successfully created a custom RSS feed for Goodreads using Node.js. You can now integrate this feed into your preferred RSS reader to stay updated with the latest content from Goodreads in a more personalized way.</p>

<p><strong>NOTE</strong>: Since Goodreads doesn’t offer a full date on the posts they list on their website, and the markup doesn’t include a full date somewhere either, posts usually show up with weird dates. Similar issues may happen if other data is missing or is incomplete in the website you’re looking to create a feed for.</p>]]></content><author><name></name></author><category term="fun" /><summary type="html"><![CDATA[One of my 2023 resolutions was to get back into the habit of reading, especially since I decided to stop being a snob and read whatever I truly wanted (even if that was some questionable fanfic-y literature). My go-to website to track the books I delve into is Goodreads. Goodreads has an amazing “news” section that’s essentially a blog where they recommend upcoming books and I usually align pretty well with what they promote over there, but the sad news is that they don’t offer an RSS feed for their news section.]]></summary></entry><entry><title type="html">Slow Zsh on macOS? Have Homebrew installed? Try this</title><link href="/work/2023/10/11/slow-zsh-macos.html" rel="alternate" type="text/html" title="Slow Zsh on macOS? Have Homebrew installed? Try this" /><published>2023-10-11T04:00:00+00:00</published><updated>2023-10-11T04:00:00+00:00</updated><id>/work/2023/10/11/slow-zsh-macos</id><content type="html" xml:base="/work/2023/10/11/slow-zsh-macos.html"><![CDATA[<p>For the past couple of years since macOS adopted Zsh as its default shell, I’ve observed a slowdown in the terminal’s availability. At first, it was barely noticeable. However, over the past three years, the time it took for a new shell to be available worsened significantly, taking almost a minute to complete.</p>

<p>In my quest to fix the issue mentioned above, I started profiling and debugging what process was impacting starting times of Zsh, in order to see if it was something added by myself, or if it was a process that could be started/loaded asynchronously. Zsh has a built in profiler which can be used by adding <code class="language-plaintext highlighter-rouge">zmodload zsh/zprof</code> at the beginning and <code class="language-plaintext highlighter-rouge">zprof</code> at the end of the <code class="language-plaintext highlighter-rouge">~/.zshrc</code> file. Initially, this indicated <code class="language-plaintext highlighter-rouge">nvm</code> to be the culprit, which ended up in having to include the following function to load it asynchronously:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvm<span class="o">()</span> <span class="o">{</span>
  <span class="nb">unset</span> <span class="nt">-f</span> nvm
  <span class="o">[</span> <span class="nt">-s</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/nvm.sh"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\.</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/nvm.sh"</span> <span class="c"># This loads nvm</span>
  nvm <span class="nv">$@</span> <span class="c"># This copies arguments after nvm</span>
<span class="o">}</span>
<span class="o">[</span> <span class="nt">-s</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/bash_completion"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\.</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/bash_completion"</span>  <span class="c"># This loads nvm bash_completion</span>
</code></pre></div></div>

<p>But even with <code class="language-plaintext highlighter-rouge">nvm</code> out of the way, the shell still took its sweet time to load and I ended up trying a myriad of other fixes to patch things up and see what was causing this issue. After several hours of googling, I stumbled upon a user called <em>bmike</em>, posting on Apple’s StackExchange, regarding a similar issue to my own: <a href="https://apple.stackexchange.com/questions/437511/how-do-i-debug-zsh-when-startup-performance-is-slow/437729#437729">https://apple.stackexchange.com/questions/437511/how-do-i-debug-zsh-when-startup-performance-is-slow/437729#437729</a>. Noticing that both the issue and the environment matched, I went ahead and looked into the responses, noticing someone mentioning <strong>Homebrew</strong> as the responsible for this issue. The user noted that the issue is happening even before the contents of <code class="language-plaintext highlighter-rouge">.zshrc</code> are executed, and realized that <strong>Homebrew</strong> includes the following lines of code in <code class="language-plaintext highlighter-rouge">.zprofile</code> (or in some cases <code class="language-plaintext highlighter-rouge">.zlogin</code>):</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'eval "$(/opt/homebrew/bin/brew shellenv)"'</span> <span class="o">&gt;&gt;</span> /Users/[your-user-name]/.zprofile
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>/opt/homebrew/bin/brew shellenv<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<p>For each shell started, the last line will repeat itself (I had almost 3000 lines of evals), ending up in a <code class="language-plaintext highlighter-rouge">.zprofile</code> file similar to this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'eval "$(/opt/homebrew/bin/brew shellenv)"'</span> <span class="o">&gt;&gt;</span> /Users/[your-user-name]/.zprofile
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>/opt/homebrew/bin/brew shellenv<span class="si">)</span><span class="s2">"</span>
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>/opt/homebrew/bin/brew shellenv<span class="si">)</span><span class="s2">"</span>
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>/opt/homebrew/bin/brew shellenv<span class="si">)</span><span class="s2">"</span>
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>/opt/homebrew/bin/brew shellenv<span class="si">)</span><span class="s2">"</span>
...
</code></pre></div></div>

<p>Cleaning up the file, leaving only a single evaluation and commenting out the first line, solves the issue. Your resulting file should look something like this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' &gt;&gt; /Users/[your-user-name]/.zprofile</span>
<span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>/opt/homebrew/bin/brew shellenv<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>

<p>It is unclear to me why <strong>Homebrew</strong> would do something like this, whether it is intentional or simply a mistake that hasn’t been fixed (at least on my installation). Nonetheless, my shell is now snappier than ever.</p>]]></content><author><name></name></author><category term="work" /><summary type="html"><![CDATA[For the past couple of years since macOS adopted Zsh as its default shell, I’ve observed a slowdown in the terminal’s availability. At first, it was barely noticeable. However, over the past three years, the time it took for a new shell to be available worsened significantly, taking almost a minute to complete.]]></summary></entry><entry><title type="html">How to take advantage of current AI innovation</title><link href="/work/2023/09/01/advantage-ai-innovation.html" rel="alternate" type="text/html" title="How to take advantage of current AI innovation" /><published>2023-09-01T01:00:00+00:00</published><updated>2023-09-01T01:00:00+00:00</updated><id>/work/2023/09/01/advantage-ai-innovation</id><content type="html" xml:base="/work/2023/09/01/advantage-ai-innovation.html"><![CDATA[<h3 id="originally-on-linkedin">Originally on <a href="https://www.linkedin.com/posts/nicolasjengler_aiintech-techtransformations-ridingtheaiwave-activity-7103089134868545536-1rej?utm_source=share&amp;utm_medium=member_desktop">LinkedIn</a></h3>

<p>After a bit of a hiatus, I’m back in the virtual town square to share some thoughts about a seismic shift that’s been reshaping the world as we know it – AI, the unstoppable force in the tech realm. Today, let’s put the personal anecdotes on hold and shine a spotlight on the game-changing force that AI has become. Buckle up, it’s quite the ride. 🌌</p>

<p>Remember how I’ve always donned the polymath-wannabe hat? That spirit of versatility that let me juggle myriad roles? Well, AI’s like that, but on turbocharge. The ability to learn, adapt, and make decisions, all at the speed of light – it’s like having a team of hyper-efficient polymaths in your digital back pocket.</p>

<p>In the grand tapestry of technology, I unwittingly ended up dipping my toes into the AI pool deeper than I initially expected. From crunching numbers to speech recognition, AI’s woven into more aspects of our lives than we realize. Its algorithms sift through mountains of data to reveal patterns that spark innovations we can only dream of.</p>

<p>But hold on to your hats, because the “AI-is-everywhere” phenomenon doesn’t come without its quirks. AI’s rapid evolution brings along its own set of hesitations and awe-inspired “whoa” moments. The question of balance emerges – how much of the decision-making reins do we hand over to AI without sacrificing our human touch?</p>

<p>Cue the whispers in the tech corridors: “AI is the answer!” “AI is the villain!” It is like walking a tightrope, similar to that headspace when you’re trying to shift mindsets. Balancing the brilliance of automation with the irreplaceable spark of human ingenuity is the name of the game. The debates rage on, the “AI-is-the-future” chant blends with the “but-humans-are-irreplaceable” mantra, and the digital world transforms before our eyes.</p>

<p>So, here’s to the present and future of AI, the technological maelstrom we’re all navigating. As I stand here, reminiscing about my own journey, I can’t help but marvel at how AI, much like product management, has journeyed from the fringes to the forefront, shaping industries, revolutionizing processes, and rewriting the rules.</p>

<p>Dive into the rabbit hole of AI’s possibilities, and let’s continue shaping a future where we harness this incredible power for the betterment of all. Here’s to embracing change, navigating uncharted territories, and riding the waves of AI-powered innovation! 🌟</p>

<p>#AIInTech #TechTransformations #RidingTheAIWave</p>]]></content><author><name></name></author><category term="work" /><summary type="html"><![CDATA[Originally on LinkedIn]]></summary></entry><entry><title type="html">Do I have my big manager-boy pants on yet?</title><link href="/management/2023/02/11/big-managemer-boy-pants.html" rel="alternate" type="text/html" title="Do I have my big manager-boy pants on yet?" /><published>2023-02-11T13:00:00+00:00</published><updated>2023-02-11T13:00:00+00:00</updated><id>/management/2023/02/11/big-managemer-boy-pants</id><content type="html" xml:base="/management/2023/02/11/big-managemer-boy-pants.html"><![CDATA[<iframe width="560" height="315" src="https://www.youtube.com/embed/E-UjBbelEqk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

<p> </p>

<p>It’s been a while since I last posted something here. Not as much time as in other ocassions but still for me it feels like ages, mostly ‘cause I’ve been through some big changes. Those changes have been both at a personal and professional level. Let’s focus on the work stuff for now ‘cause the other one is a can of worms I truly rather not open up to the internet. That last one is something I’ve been practicing lately (oversharing much?)</p>

<p>Ever since I can remember, I’ve taken pride in being a <strong>polymath-wannabe, a generalist, someone that could juggle different aspects of a whole</strong>, and that really paid off. While I always worked mostly as a developer of sorts, being able to do almost anything gave me an advantage. I was an asset to my employers. Being a generalist gave me the opportunity to learn a little about a lot. I’ve worked solo as a freelancer, I’ve worked with marketing teams, development teams, business teams, and <em>from every experience I took in as much as I was able to do so without exploding</em>.</p>

<p>I always worked as a product manager at some level without even realizing, and subconsciously I knew that managing was something I was relatively good at, but never dived too deep because my focus was somewhere else. Somewhere I felt needed my attention at the time. Somewhere I, unequivocally, thought would be more helpful for the future than my task/people-handling skills. I did design work and, although it definitely is my weakest suit, that boosted my understanding of both UX principles and UI best practices. I also did development work (a bit on the back-end, mostly on the front-end) and that taught me how to approach solutions in a logical and organized manner. After being disappointed and disenchanted with the traditional educational system, I did some self-teaching and realized I could learn virtually anything I wanted as long as I had access to the internet.</p>

<p>The “you-are-nothing scaries” is what I called the feeling I got whenever I thought of focusing mostly on management rather than development. It is likely something exacerbated because of the public discourse that says “everyone should know how to code” (when in reality it needs to be something a bit more along the lines of “everyone should learn how to think logically”) and also the “managers are useless middlepeople” misconception.</p>

<p>I retired all of my design work, and honestly it relieved me because when I looked at what I did in the past, I cringed a lot. I shouldn’t though. <strong>Past work paid for my bills, allowed me to purchase stuff I thought it wouldn’t ever be possible, taught me to push my limits</strong>, and helped me grow at my job. I also retired part of my creative coding demos. I made up my mind, I wanted to focus mostly on management, grow on how to effectively work with my teams, how to provide support for them. And here we are today.</p>

<p>The journey so far has been great, I was lucky enough to participate in projects for brands such as Pepsi, the US Open or Cardano, among others. It has also proven tricky. <strong>I’ve struggled, and sometimes I still do if I’m honest, with stripping of my predominant web development profile</strong>. I still need to concentrate mostly on helping my team from a management perspective with just a pinch of former dev-thinking rather than full-on suggesting them approaches from a technical standpoint, and I know at these times I fail my teammates at some level. It’s a long road, I guess.</p>

<p>I’m hoping this publication is the entry way for me to walk you through all the amazing stuff we’ve been building at <a href="https://waytoodigital.com/">Way Too Digital</a> these past couple of years (shout out to <a href="https://www.linkedin.com/in/agustinmaria/">Agus</a> for trusting me with obligations he thought I was responsible, sensible and smart enough to tackle. Without his trust I probably wouldn’t be where I am today professionally).</p>

<p>I’m honestly really eager to tell you some of the many stories I’ve been collecting: web3 boom, product development hurdles, amazing teammates, you name it and we can talk about it.</p>]]></content><author><name></name></author><category term="management" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">It’s morphin’ time (or the jump from web 2.0 into web3 development)</title><link href="/development/2022/10/23/web20-to-web3-development.html" rel="alternate" type="text/html" title="It’s morphin’ time (or the jump from web 2.0 into web3 development)" /><published>2022-10-23T13:00:00+00:00</published><updated>2022-10-23T13:00:00+00:00</updated><id>/development/2022/10/23/web20-to-web3-development</id><content type="html" xml:base="/development/2022/10/23/web20-to-web3-development.html"><![CDATA[<p><strong>Disclaimer:</strong> this post is structured in a reaaally weird way. I wrote this more like a stream of conciousness rather than an organized set of notes, so I beg you keep that in mind when going any further.</p>

<p>There’s been tons of articles explaining, or at least trying to encompass, what web3 actually is and how it relates to its theoretical predecessor, the so called web 2.0, a term coined in early 2000s and lately popularized at its peak around 2010 to describe how social media came into play in all this. Although this intro might be unnecessary, I feel a quick showcase of a diagram, that by now most likely 90% of the internet saw in the NFT craze from mid-to-late 2021, is necessary:</p>

<p><img src="https://www.gettingsmart.com/wp-content/uploads/2022/08/4ba40746-3ea0-42f3-8561-14cc1856e59e_D0PzD9bppJkDwgCzWr4D6R_02NhLazwsWVpN9BUL_K0L0qBTrhen0lsbe_CObfxkhZ3mHiGFNaB1MIX61dGxtb2BrH3kZNPVu4SjGeOuR0mGnFPOeMyRJnxTedvaBXauSbHtc30eFvSIqGnocae0t8s.png" alt="Read vs Read/Write vs Read/Write/Own" />
Credits to <a href="https://www.gettingsmart.com/2022/08/17/three-ways-web3-will-change-education-for-good/">GettingSmart.com</a></p>

<p>It is fair to start this blogpost by clarifying that it isn’t my intention to talk about the ethical implications or the actual practicality of the phenomenon, but rather take a look into what the development process of a decentralized app looks like based on my very own, heavily biased, experience.</p>

<hr />

<p>At the moment I began to work with a web3 related project, there was a considerable amount of information around but it sill was somewhat of an emerging trend. This initial project I took part in required to look into Ethereum-based NFTs: the client commended us to work on a web-based NFT project initially leveraging on OpenSea’s SDK to be able to provide an MVP-like experience and test the waters. Needless to say, the moment I began working on it, almost the entire team was fully unaware of what a wallet address even was, so from the get go we had a lot of homework to do.</p>

<p>For an outsider to be able to get into blockchains is somewhat of an over-complicated hurdle, as the saturation of possibilities was something that dizzied us in the beginning (see Bitcoin, Solana, Ethereum, Ethereum side-chains like Polygon, etcetera). Our first right choice tackling this was to focus solely on the inner workings of Ethereum exclusively: figuring out <strong>wallets</strong>, <strong>smart contracts</strong> and their capabilities, and how <strong>marketplaces like OpenSea</strong> played a part was key.</p>

<p>After figuring out how wallet addresses, private keys, seed phrases; and smart contracts, proxies, ERC standards, we moved on to understanding the actual process of developing smart contracts, and the limitations of <strong>Solidity</strong> as well. This part included multiple failed attempts of deploying smart contracts to testnets and manually going through the entire token creation flow we had created, a process we knew we will most likely not use but would help us figure out the ins and outs of OpenSea as the most difficult part yet would be understanding <em>what role custom smart contracts played in the ecosystem of marketplaces</em>. Surprising no one, we weren’t able to figure this out before our launch day, thus we ended up using OpenSea’s shared storefront smart contract. For context: all smart contracts deployed that create (a.k.a. mint) NFTs outside of OpenSea’s shared storefront smart contract are picked up automatically by the platform, and the wallet address that deployed the contract is considered the “creator”, making that address the only one in control to update the collection’s information (e.g.: description, name, picture, cover picture). <strong>All smart contracts that mint NFTs are considered “collections” by most marketplaces</strong>, similar to what factories are in development.</p>

<p><strong>Note:</strong> ERC standards are a particularly tricky subject, especially with themes such as fungibility of tokens. Investing many hours of research into this particular part will be absolutely worth it, trust me.</p>

<p>Long story short, the initial product launched, we relied heavily on OpenSea, but we could’ve easily relied on the actual blockchain to prevent further centralization, it was only a matter of having more time to do research and execution. There were some misses that in hindsight are obvious -for example, we used cronjobs to keep track of some transactions rather than simply going with a websocket implementation-, but we didn’t have the space to conduct proper proofs of concept because of different constraints. Nonetheless, even with this somewhat misguided approach, within the first hour of launching the product the first sale for an exclusive piece of digital art was sold, and the team was ecstatic.</p>

<p>As with every advancement on the web front, web3 has adepts and detractors, and I personally believe it is only natural to explore emerging proposals in order to be able to form an opinion and contribute to the public discourse. I don’t believe I have an ulterior motive by writing this article other thant simply logging my experience with this particular part of web history and maybe be of assistance to anyone that might be going through a similar experience in the future. The end.</p>]]></content><author><name></name></author><category term="development" /><summary type="html"><![CDATA[Disclaimer: this post is structured in a reaaally weird way. I wrote this more like a stream of conciousness rather than an organized set of notes, so I beg you keep that in mind when going any further.]]></summary></entry><entry><title type="html">From development and into product management, yet another tale</title><link href="/career/2022/03/27/from-development-into-product-management-another-tale.html" rel="alternate" type="text/html" title="From development and into product management, yet another tale" /><published>2022-03-27T13:00:00+00:00</published><updated>2022-03-27T13:00:00+00:00</updated><id>/career/2022/03/27/from-development-into-product-management-another-tale</id><content type="html" xml:base="/career/2022/03/27/from-development-into-product-management-another-tale.html"><![CDATA[<p>It is a rather common path for developers, no matter what branch they’re located in, to go from <strong>development</strong> to <strong>technical leadership</strong>, and eventually –sometimes– into <strong>management</strong>. As I’ve already stated frequently in the past, my career path has been traversed mostly solo, not in the sense of freelancing on my own but rather in the sense of never having a clear mentor to guide me through the muddy waters of the tech industry, an industry I decided to become a part of more than 10 years ago.</p>

<p>When I first started as a developer, considering that moment to be after having my first real freelancing gig, my boyfriend and mentor passed away, and ever since I’ve been doing my best to absorb the experience of others to understand what is the best way to conduct myself in whichever role I’m currently situated. My experience with an in-house role was fairly limited and lasted only about 6 months when I moved to Buenos Aires, but every instance before and after my attempt at working in a “traditional” physical office were done from a small town, giving me zero access to a face-to-face dev community, and thus limiting me to, again, getting all my knowledge and third-party experiences only from the wonderous world of the Internet.</p>

<p>I always considered myself to have a keen eye for organization and attention to detail, which gave me a great advantage not only when it came to translating designs into HTML and CSS, but also to organize my work without too much hardship. Kanban boards, ToDo lists, excerpts for clients, Gantt charts, they were never really something strange to me, and they indeed came super handy when first starting freelance jobs. This is a quality I assume naturally helped me take somewhat of a management role while developing the sites or apps I was working on, no matter if independently or as part of a team. When collaborating with a group, most project managers were thankful of this capacity, which is why I decided to value it and kept on nourishing it.</p>

<h4 id="even-if-organizing-the-tasks-in-the-project-isnt-your-main-responsibility-helping-your-team-have-a-clear-vision-of-the-current-status-and-next-steps-is-always-desired-same-goes-for-proposals-for-features-and-approaches-to-solving-different-problems-for-example">Even if organizing the tasks in the project isn’t your main responsibility, helping your team have a clear vision of the current status and next steps is always desired. Same goes for proposals for features and approaches to solving different problems, for example.</h4>

<p>As my responsibilities naturally grew when I kept on expanding my skillset as a developer, I eventually started freelancing for <a href="https://waytoodigital.com/">WayTooDigital</a>, and I induce that my contractor, Agustín, found the capacity of a developer to be able manage a team from a technical standpoint valuable, since he offered me to join in a somewhat more solid manner soon after a couple of projects. Accepting was one of the best decisions I’ve ever made, as it opened up the possibility to get my hands dirty directly with clients and the product design process altogether, and this was mostly enabled by Agustín’s trust that I was up for the task from beginning to end.</p>

<p>Meanwhile, I kept getting more involved in the lifecycle of a product and I was able to add my, and my team’s, own touch to the ideation and execution of each project, allowing us to grow both in the management department and in the latest technologies used for different types of requirements. Navigating this stage while trying to excel in both engineering and the arrangements of instructions to get a product to life is incredibly challenging, and this is where I had to make a decision on which front I wanted to be the most involved in. I eventually decided that my interest leaned towards management and this is where I steered into properly organizing what I needed on my end to provide my team with the best tools and processes for them to work and focus on their expertise areas. I was rather inexperienced in this front, so I ran through a list of what I was able to grasp were the areas that successful product managers focused on:</p>

<ul>
  <li>Helping the team in a “cross-functional” approach, considering each step of the way as a key part of a whole so they can collaborate holistically</li>
  <li>Accompanying designers and developers in depth when reviewing feature proposals or deliveries to properly prioritize and stage releases</li>
  <li>Helping clients, product owners and stakeholders understand already set realistic roadmaps with input from all parts of the team</li>
</ul>

<p>As I kept on getting deeper and deeper into this, I struggled to keep up with the requirements <em>I</em> considered were needed for my team to be successful, especially having a hard time with Proof of Worth and impostor syndrome on my end. <a href="https://twitter.com/shreyas/">Shreyas Doshi</a> helped me a great bunch with this when I read the following Twitter thread:</p>

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Proof of Worth, a gentle product management rant:<br /><br />When an early-career PM starts on a team, they might be told that they must build credibility with the builders (eng, design, analytics…)<br /><br />They must prove their worth.<br /><br />Fine advice, but it can go wrong long-term.<br /><br />1/11</p>&mdash; Shreyas Doshi (@shreyas) <a href="https://twitter.com/shreyas/status/1266797669088804865?ref_src=twsrc%5Etfw">May 30, 2020</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<p>I know I’m cutting this short, and there isn’t exactly a conclusion to this entry, as this role for me is still an active living and breathing ongoing process, but I thought that sharing how it went so far might help other people in the same place as me, who might not exactly have a mentor or someone to lean on to explore an unconventional road to an already established role in the industry.</p>

<p>Best of luck to all new managers out there! It’s a wild wild world, but we got what it takes to make the best of it.</p>]]></content><author><name></name></author><category term="career" /><summary type="html"><![CDATA[It is a rather common path for developers, no matter what branch they’re located in, to go from development to technical leadership, and eventually –sometimes– into management. As I’ve already stated frequently in the past, my career path has been traversed mostly solo, not in the sense of freelancing on my own but rather in the sense of never having a clear mentor to guide me through the muddy waters of the tech industry, an industry I decided to become a part of more than 10 years ago.]]></summary></entry><entry><title type="html">My typical day</title><link href="/workflow/2021/02/14/my-typical-day.html" rel="alternate" type="text/html" title="My typical day" /><published>2021-02-14T13:00:00+00:00</published><updated>2021-02-14T13:00:00+00:00</updated><id>/workflow/2021/02/14/my-typical-day</id><content type="html" xml:base="/workflow/2021/02/14/my-typical-day.html"><![CDATA[<h3 id="originally-on-devto">Originally on <a href="https://dev.to/nicolasjengler/my-typical-day-4mp3">Dev.to</a></h3>

<p>This post was somewhat influenced by <a href="https://css-irl.info/my-typical-day/">Michelle Barker’s post</a>, which in turn was encouraged by <a href="http://cdevroe.com/2021/01/07/my-typical-day/">Colin Devroe</a>.</p>

<p>Routine is good for me as long as I can keep a straight score, but as soon as something ruptures those habits everything falls into chaos, which is why the last couple of years (and I mean that literally, it must be around 2 years or a little bit less) that I ended up finding a system that works for me and has a decent amount of structure but still is flexible enough to allow interruptions without throwing everything into disarray.</p>

<p>Because of everything I’ve written in the previous paragraph I won’t be using hours but rather chunks of the day to describe what I do daily:</p>

<p><strong>Early morning:</strong> I wake up, do my skin care routine, and prepare some quick breakfast (it usually is a banana smoothie with strawberries or blueberries, peanut butter and honey. It can also be eggs, toasts and coffee). Once breakfast is ready I head over to my desk -lately that means the living room table of my apartment- to either read emails or organize the day. If there are bills to pay or I need to settle something, this is the moment where I try to be as productive as possible: concise answers, resolutive approaches.</p>

<p><strong>Mid-morning:</strong> Once those early morning tasks are done, I start by prioritizing what part of my work needs to be done with more urgency. Said work can either be bug fixing, feature work or documentation (depends on the client I’m working for at the moment). Some days are harder than others when it comes to having the drive to get to business, which is why I’ve been setting goals as a way to fuel my motivation. So far it’s been working good enough. At this time, if I get hungry this is the moment where I’d grab some cookies, yogurt or an apple.</p>

<p><strong>Middle of the day:</strong> Munch munch, crunch crunch. This is where I take a little time to, only lately, prepare a home-cooked meal with my boyfriend and sit and watch a short YouTube video while we have lunch together.</p>

<p><strong>Early afternoon:</strong> Where my energy is at its lowest, which I why I use this time to answer Slack messages, set up calls, and check for new emails. I try to keep all activities that don’t require much focus in this timespan so I don’t, for example, code mindlessly.</p>

<p><strong>Late afternoon:</strong> Sometimes this means 6pm, other times this means 1am. It all depends on the task I’ve been working on, how much I procrastinated or how complex it is. I been trying to keep it to 7pm at maximum, and that’s mainly because I head to the gym at the end of the day to catch a quick 50-minutes crossfit lesson (or an acting lesson if it is Tuesday) and be back home by 8 or 9pm. Once back home I take a shower, cook something with my boyfriend and our roommate, watch a TV show episode (lately that is Ryan Murphy’s “Pose”, but a couple of weeks ago it was Attack On Titan so we could catch up to the fourth season), and if possible be in bed by midnight. I used to read a decent amount a couple of years ago and I’ve been trying to get back to that but I have to admit I’ve been failing miserably (which is sad because with the whole Twilight Renaissance the internet has seen lately I would very much like to read the entirety of Midnight Sun).</p>

<p>Aaand that is a <strong>typical day for me</strong>. I obviously switch it up whenever something new comes up, like having to babysit my nephew (I became an uncle like 4 months ago, yay!) or go to a doctor’s appointment, but the overall succession of events looks like the list above.</p>

<p>Looking forward to read your typical days!</p>]]></content><author><name></name></author><category term="workflow" /><summary type="html"><![CDATA[Originally on Dev.to]]></summary></entry><entry><title type="html">How to fix unexpected gaps when printing flex-based elements in Safari</title><link href="/development/2021/02/10/fix-unexpected-gaps-printing-flexbox-safari.html" rel="alternate" type="text/html" title="How to fix unexpected gaps when printing flex-based elements in Safari" /><published>2021-02-10T14:00:00+00:00</published><updated>2021-02-10T14:00:00+00:00</updated><id>/development/2021/02/10/fix-unexpected-gaps-printing-flexbox-safari</id><content type="html" xml:base="/development/2021/02/10/fix-unexpected-gaps-printing-flexbox-safari.html"><![CDATA[<h3 id="originally-on-devto">Originally on <a href="https://dev.to/nicolasjengler/how-to-fix-unexpected-gaps-when-printing-flex-based-elements-in-safari-1hk1">Dev.to</a></h3>

<p><strong>TL;DR:</strong> if possible, switch all your Flexbox containers for block-level elements. Changing <code class="language-plaintext highlighter-rouge">display: flex</code> for <code class="language-plaintext highlighter-rouge">display: block</code> should do the trick as long as you don’t mind stacked content when printing (otherwise you’ll need to tinker around to rearrange your print layout)</p>

<p>I’ve been working for a client for almost 3 years now, his project involves students and teachers that usually <em>require printing</em> guides to use whenever <em>they don’t have an internet connection</em> to use on their devices.</p>

<p>The platform uses different modular types of content (some of that is video along text, other are images in a grid, and other components are just plain text), which is why whenever building the print styles I decided to remove any extra whitespace along with background images, plain images, iframes etcetera. When testing said print styles, everything seemed in order in major browsers like Chrome, Firefox and Edge, but Safari, for some reason, included weird large gaps in between paragraphs and/or titles and content.</p>

<p><strong>Theory 1:</strong> hidden images, iframes and grids were causing these gaps. Seemed unlikely given those elements all had the <code class="language-plaintext highlighter-rouge">display</code> property value set to <code class="language-plaintext highlighter-rouge">none</code>. After checking out these elements in the devtools, manually removing them from the DOM and printing a PDF, it was obvious this wasn’t the solution.</p>

<p><strong>Theory 2:</strong> CSS <a href="https://css-tricks.com/almanac/properties/p/page-break/">page breaks</a> needed to be set in order to get this page printing properly. After setting up <code class="language-plaintext highlighter-rouge">page-break-before</code>, <code class="language-plaintext highlighter-rouge">page-break-after</code> and <code class="language-plaintext highlighter-rouge">page-break-inside</code> property values wherever the issues arised, I tried to print a PDF using Safari but none of these changes gave me the expected results.</p>

<p><strong>Theory 3:</strong> Similar to what happens with some older JavaScript plugins when combined with Flexbox, there might be sizing issues when printing, causing large computed numbers for widths or heights. After switching all my <code class="language-plaintext highlighter-rouge">display</code> properties to use a <code class="language-plaintext highlighter-rouge">block</code> value rather than <code class="language-plaintext highlighter-rouge">flex</code>, everything showed up as it should in the generated print PDF file using Safari.</p>

<p>I was lucky enough that the print layout for this use case was simple, and stacked content was the inteded result. If you need to print layouts that are a bit more complex, you are most likely going to have to dedicate some time to rearrange your components so they play nicely.</p>]]></content><author><name></name></author><category term="development" /><summary type="html"><![CDATA[Originally on Dev.to]]></summary></entry></feed>