<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://luca3m.me/feed.xml" rel="self" type="application/atom+xml" /><link href="https://luca3m.me/" rel="alternate" type="text/html" /><updated>2026-06-21T08:01:12+00:00</updated><id>https://luca3m.me/feed.xml</id><title type="html">Luca Marturana</title><subtitle>Software Engineer focused on product development, system design, and technical foundations that scale. Interested in AI, personal finance, and legal tech.</subtitle><author><name>Luca Marturana</name></author><entry><title type="html">Models Need Focus</title><link href="https://luca3m.me/2026/06/19/models-need-focus/" rel="alternate" type="text/html" title="Models Need Focus" /><published>2026-06-19T00:00:00+00:00</published><updated>2026-06-19T00:00:00+00:00</updated><id>https://luca3m.me/2026/06/19/models-need-focus</id><content type="html" xml:base="https://luca3m.me/2026/06/19/models-need-focus/"><![CDATA[<p>One thing I realized building AI products is how much focus matters.</p>

<p>At <a href="https://sparkhq.ai">Spark AI</a>, we build features that extract structured data from documents. Most of the time results look solid, but then you hit one field that consistently misbehaves. Location in a news article, say, where three different places are mentioned and the model has to decide which one counts.</p>

<p>The instinct is to add more instructions. It helps a little. But the real problem is that you’re asking the model to do two different things in one prompt: extract fields verbatim and make a nuanced judgment. Those are different tasks, and bundling them degrades performance on both.</p>

<p>The fix is to split the prompt. One handles the straightforward extraction, another focuses exclusively on the hard field: tighter context, clearer task, room to reason through the ambiguity. Results improve immediately.</p>

<p>It’s not surprising in hindsight: asking too many things at once confuses models the same way it confuses people. A focused prompt gives the model one job to do well.</p>

<p>This has shown up consistently to us across simple and complex tasks, smaller and larger models alike. When something’s underperforming, the first question we ask now is: what are we actually asking this prompt to do, and can it be split?</p>]]></content><author><name>Luca Marturana</name></author><summary type="html"><![CDATA[One thing I realized building AI products is how much focus matters.]]></summary></entry><entry><title type="html">Fast LLM Evaluations at Spark: CSVs Over Frameworks</title><link href="https://luca3m.me/2026/01/19/fast-llm-evaluations-csvs-over-frameworks/" rel="alternate" type="text/html" title="Fast LLM Evaluations at Spark: CSVs Over Frameworks" /><published>2026-01-19T00:00:00+00:00</published><updated>2026-01-19T00:00:00+00:00</updated><id>https://luca3m.me/2026/01/19/fast-llm-evaluations-csvs-over-frameworks</id><content type="html" xml:base="https://luca3m.me/2026/01/19/fast-llm-evaluations-csvs-over-frameworks/"><![CDATA[<p><em>Note: This post was originally published on <a href="https://insights.sparkhq.ai/p/evals">Spark’s blog</a> as part of their AI Engineering Series.</em></p>

<hr />

<h2 id="tldr">TL;DR</h2>

<p>Building AI products at a startup requires speed over sophistication. We ditched complex evaluation frameworks for simple CSVs and custom scripts—and it’s been surprisingly effective. Here’s why simplicity wins: engineers label their own data and learn faster, we only evaluate high-impact features, and we can swap models in minutes. If you’re a nimble team building AI products, don’t let evaluation complexity slow you down. Start simple, stay flexible, and invest in rigor only where it really matters.</p>

<h2 id="the-evaluation-dilemma">The Evaluation Dilemma</h2>

<p>When you’re a lean team building an AI-heavy product, you very quickly run into a tension: you want rigor, but you don’t have the time, headcount, or appetite for heavyweight infrastructure.</p>

<p>At Spark, we scrape and ingest millions of documents related to large-scale energy projects and data centers. We use these documents to provide key insights like permitting regulations, social sentiment, and opposition to our customers. Initially, we developed these features solely based on cursory manual testing, but we quickly realized that in order to have a real estimate about how good our data extraction is, we needed to run evaluations.</p>

<p>Evaluation is the process by which you test that your AI software is performing tasks as you expect it to.</p>

<p>This post is about our current approach to evals: why it looks “simpler than expected,” where it’s been surprisingly effective, and how it enables us to move fast without flying blind.</p>

<h2 id="start-simple-csvs-not-frameworks">Start Simple: CSVs, Not Frameworks</h2>

<p>Our evaluation stack is intentionally unglamorous. Here’s what this looks like in practice.</p>

<p>At the core, we use plain CSV files to track labeled data. When we want to evaluate a task, we manually create a small but high-quality dataset ourselves, with engineers labeling data directly. These CSVs act as our golden datasets. In the example below, you can see a dataset snippet related to a location tagging task:</p>

<div class="my-6 overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700">
  <table class="min-w-full text-sm">
    <thead class="bg-gray-50 dark:bg-gray-800">
      <tr>
        <th class="px-4 py-3 text-left font-semibold">filename</th>
        <th class="px-4 py-3 text-left font-semibold">url</th>
        <th class="px-4 py-3 text-left font-semibold">location</th>
      </tr>
    </thead>
    <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
      <tr>
        <td class="px-4 py-3 font-mono text-xs">content-1002065.html</td>
        <td class="px-4 py-3 text-gray-600 dark:text-gray-400 text-xs">pv-magazine.com/…/pinal-county-approves…</td>
        <td class="px-4 py-3">Pinal County, AZ</td>
      </tr>
      <tr>
        <td class="px-4 py-3 font-mono text-xs">content-1002066.html</td>
        <td class="px-4 py-3 text-gray-600 dark:text-gray-400 text-xs">maricopa.gov/…/Minutes/_03142024-1847</td>
        <td class="px-4 py-3">Maricopa County, AZ</td>
      </tr>
      <tr>
        <td class="px-4 py-3 font-mono text-xs">content-1002067.html</td>
        <td class="px-4 py-3 text-gray-600 dark:text-gray-400 text-xs">federalregister.gov/…/blm-arizona-environmental…</td>
        <td class="px-4 py-3">Arizona</td>
      </tr>
    </tbody>
  </table>
</div>

<p>From there, we write lightweight, bespoke scripts that:</p>

<ul>
  <li>Run our classification code against the dataset</li>
  <li>Produces another CSV file with expected/generated task-specific outputs</li>
  <li>Computes metrics like accuracy, precision, and recall (especially for classification problems)</li>
</ul>

<p>That’s it. No dashboards, no complex orchestration, no dedicated evaluation service. From there, we usually review the metrics and the CSV output in order to understand what we can improve and iterate on.</p>

<p>We did experiment with existing evaluation frameworks early on, like popular open-source evaluation frameworks for LLM prompts. They’re powerful and have many features already included, but for our use case, they introduced more complexity. Ultimately, what matters is to evaluate the exact business logic that runs in production. It isn’t just a prompt — it may do a database lookup, custom logic, and more. Therefore, hooking others’ tools into our own code was complicated and hard to maintain.</p>

<p>Writing custom evaluation code turned out to be straightforward, easier to reason about, and far more flexible. For now, CSVs and a script that writes output to a console give us exactly what we need.</p>

<h2 id="engineers-doing-labeling">Engineers Doing Labeling</h2>

<p>Our engineers do labeling here. It is a very tedious job, but there are a couple of advantages to doing it ourselves.</p>

<p>You learn a lot about what output you really want and the data you are actually feeding to the models. This is especially valuable for building domain expertise and customer focus.</p>

<p>You also learn about how the AI reasons, what it does right and wrong, allowing you to think if iterating on the prompt is what you need – or on the output schema, or something else.</p>

<p>For example, when building our social media data ingestion feature, our engineers discovered that the model consistently failed on labelling posts as solar, wind, or battery because we used <code class="language-plaintext highlighter-rouge">projectType</code> as a schema field. Posts weren’t always related to a project, but more generally about the type of energy. The model was confused by this, so we changed the prompt and the schema to call the label <code class="language-plaintext highlighter-rouge">topic</code>, and we got some strong improvements on the results.</p>

<p>This insight came from changing a manual label—no amount of automated metrics would have surfaced this nuance early on. We adjusted our prompt and schema to explicitly handle this case, improving accuracy from 40% to 70%+ just with this change.</p>

<h2 id="evaluation-is-expensive-so-be-selective">Evaluation Is Expensive, So Be Selective</h2>

<p>The biggest constraint isn’t tooling; it’s time. For a lean team of engineers, creating and maintaining even a 100-row labeled dataset for a single task can take 2-3 hours—time we’d rather spend shipping features.</p>

<p>Labeling data, even in small quantities, is expensive. Running evaluations, maintaining datasets, and interpreting results all take real effort. Doing this for <em>every</em> piece of extracted information would slow us down dramatically.</p>

<p>So we don’t.</p>

<p>Instead, we apply evaluations only to the highest-leverage signals in our system:</p>

<ul>
  <li>Location tagging</li>
  <li>Content topic or contextual classification</li>
  <li>Other core signals that materially affect product behavior</li>
</ul>

<p>For these, correctness really matters. Small drops in quality show up immediately in user experience or downstream logic.</p>

<p>On the other hand, there are extractions where being wrong occasionally is acceptable. For example, if we slightly mis-extract metadata from a specific Facebook post, the impact is low.</p>

<p>We use a simple framework: evaluate if (1) the feature directly impacts user trust or product core value, and (2) small errors have high visibility or downstream costs. Everything else can be monitored through user feedback and production logs. In those cases, we consciously choose not to invest in full evaluation pipelines.</p>

<p>This selectivity is critical. Evaluations are a product decision as much as a technical one.</p>

<h2 id="knowing-whats-happening-in-production">Knowing What’s Happening in Production</h2>

<p>One of the biggest benefits of even a simple evaluation setup is clarity.</p>

<p>Having labeled datasets and repeatable evaluation code gives us a concrete understanding of how our system behaves—not just an intuition. When a user complains about a misclassified document, we can add it to the dataset, tweak the prompt, and verify that our metrics stay on track.</p>

<p>This forces us to be explicit about what “good” means for each task. Metrics are imperfect, but they anchor conversations that would otherwise be vague and subjective.</p>

<h2 id="model-swapping-without-fear">Model Swapping Without Fear</h2>

<p>Another major upside of our approach is how easy it makes model iteration.</p>

<p>We’ve built a small in-house framework that allows every part of the app to run the same query against different models. Evaluations are fast and repeatable; we can swap models—different providers, versions, or prompting strategies—and immediately see how they compare on our golden datasets.</p>

<p>This has been invaluable. It lets us:</p>

<ul>
  <li>Make cost–quality trade-offs deliberately</li>
  <li>Respond quickly when models change upstream</li>
  <li>Avoid over-committing to any single vendor or approach</li>
</ul>

<p>Crucially, this only works because evaluations are cheap to run and easy to understand.</p>

<h2 id="pragmatism-over-perfection">Pragmatism Over Perfection</h2>

<p>Our evaluation setup is not “best practice” in the abstract sense. It’s not designed to scale infinitely, and it’s not meant to impress anyone browsing our stack.</p>

<p>What it does do is match our current reality:</p>

<ul>
  <li>A nimble team</li>
  <li>A fast-moving product</li>
  <li>AI systems that must be reliable in specific, high-impact areas</li>
</ul>

<p>As Spark grows, this approach will evolve. CSVs may turn into databases, scripts into services, consoles into dashboards. But the underlying philosophy won’t change: invest in evaluation where it buys real leverage, and keep everything else as simple as possible.</p>

<p>If you’re just starting to build with AI, don’t be scared of evaluations—you don’t need scale or big investments. Start small; it’s already valuable.</p>

<h2 id="key-takeaways">Key Takeaways</h2>

<p>For those just starting to build AI features, here are the principles we’d recommend:</p>

<ol>
  <li>Start with CSVs and simple scripts for evaluations—fight the urge to build complex infrastructure upfront.</li>
  <li>Have engineers label their own data, at least initially—the learning is invaluable</li>
  <li>Be ruthlessly selective about what you evaluate—not everything deserves a full pipeline.</li>
  <li>Make evaluations fast and repeatable so you can experiment with confidence</li>
  <li>Let your setup evolve with your needs—simple today doesn’t mean simple forever.</li>
</ol>]]></content><author><name>Luca Marturana</name></author><summary type="html"><![CDATA[Note: This post was originally published on Spark’s blog as part of their AI Engineering Series.]]></summary></entry><entry><title type="html">Working with AI</title><link href="https://luca3m.me/2025/04/23/working-with-ai/" rel="alternate" type="text/html" title="Working with AI" /><published>2025-04-23T00:00:00+00:00</published><updated>2025-04-23T00:00:00+00:00</updated><id>https://luca3m.me/2025/04/23/working-with-ai</id><content type="html" xml:base="https://luca3m.me/2025/04/23/working-with-ai/"><![CDATA[<p>Over the past year, I’ve been working a lot more with AI. I’m not a machine learning or deep learning expert — and honestly, I never set out to be — but in the last few years AI has become a technology you just can’t ignore. And actually learning how it works has actually been a lot of fun.</p>

<p>I’ve already written <a href="/2025/03/28/programming-in-the-ai-age/">here</a> about how I use AI for coding, but today I want to share a few lessons from a slightly different angle: <strong>building software that leverages AI</strong>.</p>

<h1 id="build-your-own-golden-dataset">Build your own golden dataset</h1>

<p>If you want AI to perform a task for you, <strong>you first have to do the task yourself</strong>.</p>

<p>It may seem easier start writing prompts and check the results, but without a proper dataset to measure the performance you can’t have confidence if it’s working well or not.</p>

<p>Building such a dataset is very tedious, especially for software engineers (like me) who love to automate everything, but it is important.</p>

<p><strong>For example:</strong> if you want the AI to classify documents and assign labels, you’ll need to manually label at least 100–200 documents yourself. Basically, you’re building a <em>questions and answers</em> set that will give you a <strong>way to measure</strong> if the AI is doing the job properly.</p>

<p>Without a solid dataset like this, you’re blind. You can test a few inputs but you’ll have no real confidence that it’s going to work for your users at scale.</p>

<p>So my recommendation is: <strong>start by building a small but good dataset</strong>, then write code that checks if the AI’s output matches what you expect. It gives you a reliable foundation to build and test against.</p>

<h1 id="ask-for-reasoning">Ask for reasoning</h1>

<p>When working with AI, it’s very useful to ask not just for an answer, but for a <strong>reasoning field</strong> or also known as <strong>chain of thought</strong> in the output — a little explanation of how the AI got there.</p>

<p>This helps in two ways:</p>
<ol>
  <li>it actually makes the AI <strong>reason</strong> better internally. When it generates tokens (words), it <em>thinks</em> better if you encourage it to explain itself.</li>
  <li>it helps you <strong>debug</strong> your prompts. By reading the reasoning, you can quickly spot if the AI misunderstood what you wanted — and refine your instructions.</li>
</ol>

<p>In my case, analyzing the reasoning output made it clear when the AI didn’t fully get my intent. Without that feedback, I would’ve been trying things out blindly.</p>

<p>A small tip if you want to keep things clean: you can ask the AI to format its output in <strong>JSON</strong>, or use simple <strong>HTML/XML tags</strong> to separate the real response from the reasoning part. That way, your app can easily parse and ignore the reasoning when it’s not needed.</p>

<h1 id="be-lean-with-frameworks">Be lean with frameworks</h1>

<p>Right now, there’s a <strong>huge explosion</strong> of AI frameworks. There are tools to evaluate model responses, to abstract building RAGs, to build agents… you name it.</p>

<p>But my advice is simple: <strong>stay lean</strong>.</p>

<p>Most of these frameworks are very early, and their abstractions might not survive long-term. It’s better to get closer to the metal — build your own abstraction and understand how things work at a low level.</p>

<p>Writing some basic evaluation scripts yourself is usually easy, and it has a huge benefit:
You’ll naturally design your code so it’s easier to test and evaluate — which is critical when building anything AI-driven.</p>

<p>As you build, I think there are two things you absolutely want:</p>
<ol>
  <li><strong>Flexibility to swap LLM models easily</strong>, depending on cost or performance.</li>
  <li><strong>Evaluations for every core part of your app</strong>, so you always know how well your AI is performing.</li>
</ol>

<h1 id="conclusion">Conclusion</h1>

<p>Working with AI requires a different mindset than traditional software development. Building good datasets, understanding how models reason is definitely something new I needed to learn.</p>

<p>Overall, I’m excited for what’s ahead in this space. The technology is evolving rapidly and will unlock lots of opportunities to create new kinds of products! 🚀</p>]]></content><author><name>Luca Marturana</name></author><summary type="html"><![CDATA[Over the past year, I’ve been working a lot more with AI. I’m not a machine learning or deep learning expert — and honestly, I never set out to be — but in the last few years AI has become a technology you just can’t ignore. And actually learning how it works has actually been a lot of fun.]]></summary></entry><entry><title type="html">Programming in the AI Age</title><link href="https://luca3m.me/2025/03/28/programming-in-the-ai-age/" rel="alternate" type="text/html" title="Programming in the AI Age" /><published>2025-03-28T00:00:00+00:00</published><updated>2025-03-28T00:00:00+00:00</updated><id>https://luca3m.me/2025/03/28/programming-in-the-ai-age</id><content type="html" xml:base="https://luca3m.me/2025/03/28/programming-in-the-ai-age/"><![CDATA[<p>Recently, I’ve been using AI extensively for my coding tasks. Mainly using <a href="https://www.cursor.com/">Cursor</a> IDE and its super-powered tab-completion that makes writing code much easier.</p>

<h1 id="ai-tab-completion">AI Tab completion</h1>

<p>It seems it reads my mind in a certain way. When I start a code change, it will automatically suggest very relevant completions to finish it.</p>

<div class="flex justify-center mb-5">
  <iframe width="560" height="315" src="https://www.youtube.com/embed/nXEVkU60UY8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
</div>

<p>As you can see in the video above, this makes me much more productive and writing code is less tedious. AI understands the intention of my change and provides very relevant completions that I can simply accept. This feature also helps reduce the amount of boilerplate code I need to write myself, which is very welcome.</p>

<p>But I wanted also to try something different — what if AI could write most of the code for me?</p>

<h1 id="rewriting-css-of-this-website">Rewriting CSS of this website</h1>

<p>I started this website a decade ago, when <a href="https://getbootstrap.com/">Bootstrap</a> was the state-of-the-art CSS framework and <a href="https://bower.io/">Bower</a> was the go-to tool for managing frontend code dependencies.</p>

<p>Many things changed since then, at certain point Bower has been retired and Bootstrap is still good but a bit bloated for what I need. I kept hanging on to it because I didn’t have time to rewrite this blog from scratch.</p>

<p>Recently I started a couple of projects and <a href="https://tailwindcss.com/">Tailwind</a> looked like a much better alternative CSS framework, so I wanted to convert my blog to use it as well.</p>

<p>Using Cursor <a href="https://www.cursor.com/features">Agent mode</a> mode you can ask to write code for you by explaining in plain english what you want and it performs the changes you asked across your codebase.</p>

<p>I used the following prompt to rewrite my Jekyll layouts:</p>

<blockquote>
  <p>Rewrite this layout using Tailwind instead of Bootstrap. Keep the structure similar but it does not need to be exactly the same.</p>
</blockquote>

<p>The result was good enough to start with, though I had to tweak small things here and there. Still, it was remarkable that I was able to rewrite this website without knowing all the intricacies of Tailwind. I still don’t know the framework very deeply, to be honest. 🙂</p>

<h1 id="writing-an-ios-app">Writing an iOS app</h1>

<p>Sometimes I play card games with family and I prefer to use an app to keep track of scores — I know it sounds very nerdy! There are a ton of them in the App store but there was none I really liked. So I thought, why don’t I just write one myself?</p>

<p>It has been a while since I wrote any iOS code, so I thought it would be a good idea to use AI to help me.</p>

<p>Using Cursor Agent mode I used prompts like:</p>

<blockquote>
  <p>Show a list of players representing scores in a card game. For each player show the score and buttons to increase and decrease it.</p>
</blockquote>

<blockquote>
  <p>When the user taps the score, show a modal view that allows to change the score via a text field input</p>
</blockquote>

<p>And so forth.</p>

<p>Not everything worked on the first try. Here and there I had to dig into SwiftUI to understand why a layout wasn’t working as expected or why a tap didn’t trigger what the code was supposed to do.</p>

<p>Nevertheless, the results were remarkable. I was able to write a fully functional app in just a few days, despite having limited knowledge of Swift, SwiftUI, and SwiftData. It wasn’t just a prototype either — I successfully <a href="https://apps.apple.com/us/app/tallup/id6743003388">shipped</a> it to the App Store!</p>

<p>While doing this, I also noted that AI is less knowledgeable about iOS development compared to web development. I guess this is because there is less public data available of iOS code.</p>

<h1 id="conclusion">Conclusion</h1>

<p>It’s a very exciting time to be building! Turning ideas into code is much easier and faster than before. After leaving my previous job, I started coding daily and have been enjoying it much more, mainly due to Cursor’s powerful auto-completion and the ability to have AI write code for me. While I still need to double-check and sometimes fix AI-generated code manually, it has given me a tremendous productivity boost.</p>]]></content><author><name>Luca Marturana</name></author><category term="english," /><category term="tech" /><category term="programming" /><category term="artificial intelligence" /><category term="software development" /><category term="future of coding" /><summary type="html"><![CDATA[Exploring how artificial intelligence is transforming software development and the role of programmers in an AI-augmented future]]></summary></entry><entry><title type="html">Come rendere smart il termostato Immergas CARV2</title><link href="https://luca3m.me/2024/03/28/come-rendere-smart-termostato-immergas-carv2/" rel="alternate" type="text/html" title="Come rendere smart il termostato Immergas CARV2" /><published>2024-03-28T00:00:00+00:00</published><updated>2024-03-28T00:00:00+00:00</updated><id>https://luca3m.me/2024/03/28/come-rendere-smart-termostato-immergas-carv2</id><content type="html" xml:base="https://luca3m.me/2024/03/28/come-rendere-smart-termostato-immergas-carv2/"><![CDATA[<p>Recentemente ho acquistato una casa dotata del termostato <a href="https://www.amazon.it/Comando-Amico-Remoto-Cronotermostato-Immergas/dp/B01LX0HJUC">Immergas CARV2</a>.</p>

<p>Desideravo aggiornarlo con un modello smart, tuttavia ciò si è rivelato un compito non così semplice a causa delle sue funzioni di controllo della temperatura dell’acqua sanitaria e della complessa integrazione con la caldaia.</p>

<p>Per fortuna ho scoperto che il termostato dispone di un morsetto denominato TEL, il quale è utilizzato da un accessorio venduto separatamente. Questo accessorio consente di collegare e scollegare il termostato tramite telefono.</p>

<p>Tuttavia, l’accessorio non risulta particolarmente utile in quanto opera esclusivamente tramite la rete telefonica tradizionale: riceve una chiamata e attiva il termostato.</p>

<p>Il morsetto TEL, che viene attivato, è essenzialmente un interruttore on/off. È così che mi è venuta un’idea: perché non attivare quell’interruttore con uno smart switch?</p>

<p>Ed ha funzionato! A seguire vi spiego come fare</p>

<h1 id="componenti-e-collegamento">Componenti e collegamento</h1>

<p>I componenti che ho usato sono i seguenti:</p>

<ul>
  <li><a href="https://www.amazon.it/dp/B0CLND5Q18/ref=twister_B0CP8XXBTQ?_encoding=UTF8&amp;psc=1">Interruttore smart Sonoff</a> (altri marchi vanno bene pure)</li>
  <li><a href="https://www.amazon.it/FINDER-40-52-9-012-0000-Finder/dp/B0018L3QJW/ref=sr_1_30?__mk_it_IT=ÅMÅŽÕÑ&amp;crid=1DLL3AS4YCZPZ&amp;dib=eyJ2IjoiMSJ9.D1HdKUPWFTBWjPcgoSOQaoryJJAPbds2kud855fOumDdY09GwDpixG7RhKJyi4Bqim47CpWoHRm8RCQOgE0Vjozcexey5LQnrRN15i-hmxU.qu4RJ_6h9NNhBtMGUC9XN5hnMYT1XCSDwQirz4Y9O1E&amp;dib_tag=se&amp;keywords=rele%2B220v&amp;qid=1711573530&amp;s=industrial&amp;sprefix=rele%2B220%2Cindustrial%2C123&amp;sr=1-30&amp;th=1">Relé</a>, questo è necessario perché l’uscita a line out del Sonoff non sarebbe adatta come ingresso al CAR</li>
  <li><a href="https://www.amazon.it/Gebildet-5pcs-Impermeabile-Interruttore-Pulsante/dp/B088D933J2/ref=sr_1_9?dib=eyJ2IjoiMSJ9.NhyY4Uk9bDwZj2zW2mk8DbN28tzITgMauAGtM5Is_TSn_O7M0klWrxcSJwC9N9RHYXyWFMVQ9kdWnguQKaBJibXWVjkzQKJt5ytUbq9XxHdki83q5ZETN_DTf2GEs-PF-koafUgv1cqAv3KB1F11-BfVYmvrNaYx9AHo2RZoTPb4lOLf3rw0VDQXkznZt7-1T6e4hVKO9expfVCAP4u_G4ZgMbnEuiRAFNItCu8hTG9tT3l9FPiHC39tPFgfqVwaao_Ybwg4tVerS6s9UGEZ1u4id1o1m01eHPGqMVwO13A.0t5ME30wp08fk6RDy8jrocMfIN-2JOKPnB5R-qScdE0&amp;dib_tag=se&amp;keywords=mini+interruttore&amp;qid=1711573597&amp;sr=8-9">Un interruttore fisico</a>, per azionare manualmente il Sonoff</li>
</ul>

<div class="flex flex-col items-center mt-8 mb-8">
  <img src="/assets/images/carv2.png" alt="Schematico di collegamento dei componenti" class="max-w-[500px]" />
  <div class="text-center text-sm text-gray-600 dark:text-gray-400 mt-2">
    Schema di collegamento dei componenti per rendere smart il termostato CARV2
  </div>
</div>

<p>In questo modo è possibile accendere e spegnere il termostato tramite l’interruttore smart. Infatti quando l’uscita del Sonoff è accesa, il relé chiude il circuito del morsetto TEL del CARV2 che permette di configurarlo in due modi:</p>

<ul>
  <li>Imposta il riscaldamento acceso alla temperatura comfort</li>
  <li>Imposta il riscaldamento secondo la programmazione comfort/economy giornaliera configurata</li>
</ul>

<p>Potete trovare tutti questi dettagli sul <a href="https://www.immergas.com/media/Accessorio/63cc1ddc3fdcb6a15d9d0a8c/CAR_V2-1038958_001_01856.pdf">manuale</a> dell’apparecchio.</p>

<div class="bg-yellow-200 dark:bg-yellow-800 rounded-lg p-4 mb-6">
  <span class="font-bold">Attenzione</span>: il CARV2 deve essere in modalità <span class="font-bold">estiva</span> per poter accendere e spegnere il riscaldamento in maniera remota. Per questo motivo secondo me è utile avere un interruttore fisico in modo da usare sempre quello per accendere/spegnere il riscaldamento
</div>

<h1 id="conclusioni">Conclusioni</h1>

<div class="flex justify-center">
  <iframe width="560" height="315" src="https://www.youtube.com/embed/jShwcY1Htkk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
</div>

<p>Il Sonoff può essere collegato ad HomeKit, Alexa o Google Home, consentendo così di creare automazioni che attivano o disattivano il termostato in base alla presenza di persone in casa, a orari predefiniti, e così via.</p>

<p>Anche se i termostati smart come <a href="https://www.ecobee.com/en-us/">Ecobee</a> o <a href="https://store.google.com/it/product/nest_learning_thermostat_3rd_gen?hl=it&amp;pli=1">Nest</a> offrono sicuramente funzionalità più avanzate, già con questa configurazione si possono ottenere diversi vantaggi tramite le automazioni. Ad esempio, ho impostato il termostato in modo che si spenga quando usciamo di casa e si riaccenda al nostro ritorno.</p>]]></content><author><name>Luca Marturana</name></author><category term="italian" /><summary type="html"><![CDATA[Come trasformare un termostato Immergas CARV2 in un termostato smart utilizzando un interruttore Sonoff e un relé, per controllarlo da remoto e creare automazioni.]]></summary></entry><entry><title type="html">Why I chose Hey</title><link href="https://luca3m.me/2021/03/13/why-i-chose-hey/" rel="alternate" type="text/html" title="Why I chose Hey" /><published>2021-03-13T00:00:00+00:00</published><updated>2021-03-13T00:00:00+00:00</updated><id>https://luca3m.me/2021/03/13/why-i-chose-hey</id><content type="html" xml:base="https://luca3m.me/2021/03/13/why-i-chose-hey/"><![CDATA[<p>As work is becoming remote, I’m realizing that writing skills are more and more essential. To further practice my skills of writing concisely and effectively, I’m going to try writing in a blog post here and there. I’m gonna start this one by talking about why I chose Hey for my email.</p>

<p>Last year, I realized that letting Google own my email is a <strong>bad idea</strong>, more so if many many people do it. If you think about it, Google is able to know about every single item I buy on Amazon, or which bank accounts I use and how much money I make, just looking at the notifications I receive from such services. This is bad for my privacy and at scale is bad for everyone.</p>

<p>I also realized that the model of having an email protocol and an email client is broken, it limits innovation because client developers have to work on top of protocol designed decades ago. For example, using Apple Mail for Gmail does not give you push notifications for new messages if you want them, because email protocols don’t offer this use case.</p>

<p>I wanted a vertically integrated solution that would give me a great user experience and I want to pay for it in order to have my <strong>privacy</strong>.</p>

<p>There are many email providers but many of them strive to have support for legacy protocols and don’t do much more than that, their apps for example are subpar. So my focus quickly narrowed down to iCloud and Hey.</p>

<p>The former because I already pay for it, in order to store safely my photos, so I could get email there for <em>free</em>. But I thought that the interface of Mail is not going to change much for two reasons:</p>

<ol>
  <li>Apple Mail has to support the legacy IMAP and SMTP protocols, thus the User Experience isn’t going to change anytime soon</li>
  <li>Apple then can’t leverage a vertical integration with iCloud to provide a better experience, and even if they want to do so, the benefit will be trivial because most people use Gmail anyway</li>
</ol>

<p>Hey instead, has the same privacy focus that Apple has and on top of it, they created a vertically integrated platform. This platform allows them to build what they have today: Imbox, Screener, Feed, Paper Trail and my bet is that it will allow them to iterate at a faster speed. Also, they are a small business that does not need to compete at Apple and Google scale, so they can keep innovating as long as enough people pay for Hey.</p>

<p>This is where I placed my bet then, and so far I don’t regret it</p>]]></content><author><name>Luca Marturana</name></author><category term="english" /><summary type="html"><![CDATA[As work is becoming remote, I’m realizing that writing skills are more and more essential. To further practice my skills of writing concisely and effectively, I’m going to try writing in a blog post here and there. I’m gonna start this one by talking about why I chose Hey for my email.]]></summary></entry><entry><title type="html">Operating systems are a huge pile of technical debt</title><link href="https://luca3m.me/2016/09/01/operating-systems/" rel="alternate" type="text/html" title="Operating systems are a huge pile of technical debt" /><published>2016-09-01T00:00:00+00:00</published><updated>2016-09-01T00:00:00+00:00</updated><id>https://luca3m.me/2016/09/01/operating-systems</id><content type="html" xml:base="https://luca3m.me/2016/09/01/operating-systems/"><![CDATA[<p>Developers are responsible for creating new, powerful software. This is what we do, day in and day out. But much of the software we create is based on the work of others. It’s not only their software from yesterday, but also from years or decades before. That creates a complex set of challenges when it comes to understanding the behavior of our own software, let alone someone else’s.</p>

<p>In this article I’m going to show you a situation that I ran into recently. It gave me the opportunity to do a little troubleshooting in Linux, and even understand the different ways you can create new processes on Linux.</p>

<h2 id="sysdig-host-instrumentation">Sysdig host instrumentation</h2>

<p>First let’s recap a little bit how the sysdig open source tool works, as well as our commercial agent that runs on top of it.</p>

<p>Our core piece of technology is the sysdig kernel module. It’s loaded into the kernel and it traces every system call happening on the host. For more details information you can read our <a href="https://sysdig.com/blog/sysdig-vs-dtrace-vs-strace-a-technical-discussion/">previous blog post</a> on this.</p>

<p>This flow of events then goes to our sysdig userspace utility that reads them, parses them and allows you to do filtering and scripting on top.For example sysdig is able to isolate all network related activity of your database, sort processes based on docker containers, or tail the logs of your webserver. You can find a cheatsheet of common tasks <a href="https://sysdig.com/blog/linux-troubleshooting-cheatsheet/">here</a>.</p>

<p>Our commercial product uses an agent is built on top of sysdig technology. But it uses system calls for a different purpose: we aggregate system, application, container, and statsd metrics across thousands of hosts and tens of thousands of containers. These are sent to our <a href="https://www.sysdig.com">backend service</a>, where you chart them, analyze, setup alerts and so on.</p>

<p>Ok, enough background, let’s get into the story.</p>

<h2 id="the-tale-statsd-is-broken">The tale: statsd is broken</h2>

<p>Everything started with a customer who was not able to see statsd metrics being collected from our agent. Our agent has a statsd capture capability that should <a href="https://sysdig.com/blog/how-to-collect-statsd-metrics-in-containers/">just work</a> - no additional endpoint needed. But it didn’t work for our customer. They were using a php-fpm configuration behind nginx.</p>

<p>Usually we ask customers to send us a sysdig capture, which is similar to a Wireshark trace though instead of just packet info it contains rich system call data.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysdig -w capture.scap
</code></pre></div></div>

<p>With it, we can troubleshoot it offline and not require ssh access to their host. But the capture didn’t have any issues - our agent was correctly parsing statsd protocol from the system calls.</p>

<p>I decided to simulate their environment locally on my host. I launched a setup with nginx + php-fpm using docker-compose. Our agent detected the statsd protocol and was worked fine. I was no closer to figuring out why it wasn’t working for our customer.</p>

<p>Then, I had a lucky breakthrough: by a chance I restarted the php-fpm engine while the agent was running and suddenly statsd wasn’t working anymore!</p>

<p>So I was able to replicate it, quite good starting point. I now understood that the reason we weren’t seeing statsd metrics was that php-fpm didn’t have the appropriate container metadata (namely: ID, image name and labels) attached. If statsd traffic does not come from a container our agent does not forward it to our embedded statsd server. That’s because non-containerized processes running in the host are able to reach the agent using UDP, so forwarding it would just duplicate data. A bug like this impacts sysdig open source too, so I launched it, filtered for statsd traffic and asked for container metadata (using -pc command line argument):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># sysdig -pc proc.name = php-fpm and fd.sport = 8125
5021 07:22:37.854474986 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &lt; connect res=0 tuple=127.0.0.1:41816-&gt;127.0.0.1:8125
5022 07:22:37.854475663 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &gt; fcntl fd=5(&lt;4u&gt;127.0.0.1:41816-&gt;127.0.0.1:8125) cmd=5(F_SETFL)
5023 07:22:37.854475780 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &lt; fcntl res=0(&lt;3t&gt;:::9000)
5024 07:22:37.854478368 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &gt; sendto fd=5(&lt;4u&gt;127.0.0.1:41816-&gt;127.0.0.1:8125) size=34 tuple=NULL
5025 07:22:37.854499400 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &lt; sendto res=34 data=app.metrics.foo:0.38912133891213|g
5032 07:22:37.854586118 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &gt; close fd=5(&lt;4u&gt;127.0.0.1:41816-&gt;127.0.0.1:8125)
5033 07:22:37.854586634 1 phpfpmalpine_php_1 (d7bb71f7610b) php-fpm (11641:7) &lt; close res=0
</code></pre></div></div>

<p>Here’s what it looked like after restarting php-fm:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>169694 07:22:43.494058726 3 host (host) php-fpm (11830:7) &lt; connect res=0 tuple=127.0.0.1:40687-&gt;127.0.0.1:8125
169695 07:22:43.494059466 3 host (host) php-fpm (11830:7) &gt; fcntl fd=5(&lt;4u&gt;127.0.0.1:40687-&gt;127.0.0.1:8125) cmd=5(F_SETFL)
169696 07:22:43.494059628 3 host (host) php-fpm (11830:7) &lt; fcntl res=0(&lt;6&gt;)
169697 07:22:43.494062421 3 host (host) php-fpm (11830:7) &gt; sendto fd=5(&lt;4u&gt;127.0.0.1:40687-&gt;127.0.0.1:8125) size=34 tuple=NULL
169698 07:22:43.494085960 3 host (host) php-fpm (11830:7) &lt; sendto res=34 data=app.metrics.foo:0.71194379391101|g
169705 07:22:43.494119291 3 host (host) php-fpm (11830:7) &gt; close fd=5(&lt;4u&gt;127.0.0.1:40687-&gt;127.0.0.1:8125)
169706 07:22:43.494119602 3 host (host) php-fpm (11830:7) &lt; close res=0
</code></pre></div></div>

<p>So the container info is parsed correctly only when sysdig starts and it reads processes metadata from <code class="language-plaintext highlighter-rouge">/proc</code> directory but not if a process starts while sysdig or the agent is running. This didn’t happen on the capture file from the customer because it was taken in the former case.</p>

<p>How is a bug like this even possible? It couldn’t be unseen for so long, so I dug into the new php-fpm process pid and captured all the events related to it. Here I found something odd: the event that creates the process is not clone but fork:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysdig -r php-fpm.scap proc.pid = 11830

134079 07:22:41.219236734 3 php-fpm (11830) &lt; fork res=0 exe=php-fpm args= tid=11830(php-fpm) pid=11830(php-fpm) ptid=11801(php-fpm) cwd=/var/www/html fdlimit=1048576 pgft_maj=0 pgft_min=0 vm_size=39816 vm_rss=4796 vm_swap=0 comm=php-fpm cgroups=cpuset=/docker/d7bb71f7610b01172a9b87cd09ac04709d4239f2acc73f6e237adbafc30993... flags=0 uid=0 gid=0 vtid=7 vpid=7
</code></pre></div></div>

<p>Why fork? On Linux, clone is the system call used to create new processes. And it’s the only system call I’d seen used so far.</p>

<p>Doing a bit of research I found this <a href="https://unix.stackexchange.com/questions/199686/fork-vs-clone-on-2-6-kernel-linux">nice answer on stackoverflow</a> stating that actually fork is the old system call used in linux to create new processes that has been superseded by clone.</p>

<p>Then I went on the code we use to parse the clone event and I found that actually we were parsing cgroups info only on clone events and not fork or vfork.</p>

<p><a href="https://github.com/draios/sysdig/commit/1d6bf842741fbcfc0c843860259356172820d08b">Fixing it</a> made everything work.</p>

<h2 id="conclusion">Conclusion</h2>

<p>This story reminded me a quote by <a href="https://twitter.com/justincormack">Justin Cormack</a> I heard at QCon London late last year:</p>

<blockquote>
  <p>“Operating systems are just a kind of technical debt”</p>
</blockquote>

<p>This is absolutely true: Linus Torvalds’ mantra is “never break userspace”. This makes software compatible for a decade and more, making Linux the reliable operating system we trust and love. The downside is that part of the life of a system software engineer is dealing with traces from the past of Linux history</p>

<h2 id="side-note">Side note</h2>

<p>Why php-fpm was using fork? It wasn’t the one to blame for it. Alpine linux uses muslc instead of glibc. Digging deeper, I found it uses the fork system call to implement the fork() function instead of clone, as glibc does. It’s probably because clone is more complicated to use.</p>

<p><em>Note: this blog post has been originally published on <a href="https://sysdig.com/blog">Sysdig official blog</a></em></p>]]></content><author><name>Luca Marturana</name></author><category term="english" /><summary type="html"><![CDATA[Developers are responsible for creating new, powerful software. This is what we do, day in and day out. But much of the software we create is based on the work of others. It’s not only their software from yesterday, but also from years or decades before. That creates a complex set of challenges when it comes to understanding the behavior of our own software, let alone someone else’s.]]></summary></entry><entry><title type="html">Junior and senior engineers</title><link href="https://luca3m.me/2015/07/04/junior-vs-senior-engineers/" rel="alternate" type="text/html" title="Junior and senior engineers" /><published>2015-07-04T00:00:00+00:00</published><updated>2015-07-04T00:00:00+00:00</updated><id>https://luca3m.me/2015/07/04/junior-vs-senior-engineers</id><content type="html" xml:base="https://luca3m.me/2015/07/04/junior-vs-senior-engineers/"><![CDATA[<p>3 years ago I got my first job as software engineer, there is a huge difference between writing university projects and shipping <strong>real working</strong> software, I learnt a lot of things that forged my mind.</p>

<p>I started from writing little features and end up to bigger ones. Step by step I found patterns better then others, and learn how to write better quality code.</p>

<p>I dealt with different kind of software, written by fellow juniors and seniors engineers and I saw different approaches about dealing with problems.</p>

<h2 id="code-quality">Code quality</h2>

<p>A great junior engineer is very idealistic, he wants to write very clean code with blending edge tools. He spots a lot of troubles or bad practices on already written production code and wants to rewrite everything to make it better.</p>

<p>A senior engineer has written a lot of software, he agrees with the junior about bad written code but does not want to change it, because <strong>it works</strong>. A junior developer hates this word but it’s true. If something works, you don’t need to waste your time changing it, and the best explanation I’ve read is this:</p>

<blockquote>
  <p>“Well,” they say, “look at this function. It is two pages long! None of this stuff belongs in there! I don’t know what half of these API calls are for.” Yes, I know, it’s just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I’ll tell you why: <em>those are bug fixes</em></p>
</blockquote>

<blockquote>
  <p>The idea that new code is better than old is patently absurd. Old code has been used. It has been tested. Lots of bugs have been found, and they’ve been fixed. There’s nothing wrong with it. It doesn’t acquire bugs just by sitting around on your hard drive.</p>
</blockquote>

<blockquote>
  <p>Quote from <a href="https://www.joelonsoftware.com/articles/fog0000000069.html">Joel Spolsky</a></p>
</blockquote>

<p>So do we have to stay always with the same software because it works? I did two rewrite on my career, one succeeded and one not. Why? My answer now is that you need to rewrite if your software does not fit your scenario anymore: does not scale, cannot provide more features or whatever. There is a subtle balance between the <strong>bug shower</strong> you will get and the gain you will accomplish with your change. If it’s worth to do it, you will succeed, if it’s not worth you will probably fail.</p>

<h2 id="tools">Tools</h2>

<p>A senior engineer has worked with a bunch of technologies. Sometimes it’s a trap, because he tends to deal with a problem using always the same tools, sometimes they are still good, sometimes not.</p>

<p>A junior engineer has a great quality: <em>he knows nothing</em>. He sees problems for the first time and he can find solutions from a different angle that experienced engineers don’t find. Junior engineers are amazed by new tools of any kind: languages, databases, frameworks etc.</p>

<p>Listening to them can led your project to new levels, fighting the attitude of staying inside the <strong>well known</strong> circle.</p>

<h2 id="new-projects">New projects</h2>

<p>When comes to a new project a junior engineer starts to write everything from scratch. Seniors instead tends to start from a similar tool and modify it to fullfill required needs. Why?</p>

<p>The main problem is that reading software is harder than writing it, junior finds hard to read software written by others and so he prefers to start from scratch.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I learnt that any production software is always <strong>bad</strong>, it has some bad practices, 1000 lines of code functions, uses a database not good for the scope and more. This because when you begin a project it’s like starting a journey without knowing the destination. Software it’s like a sculpture, you start from a blank screen and begin to engraving your code. You discover step by step what your software should do and you can’t start again from scratch at any change.</p>

<p>The difference between a good software and a bad one is that a well written software is easier to change even if it has some bad practices inside.</p>]]></content><author><name>Luca Marturana</name></author><category term="english" /><summary type="html"><![CDATA[3 years ago I got my first job as software engineer, there is a huge difference between writing university projects and shipping real working software, I learnt a lot of things that forged my mind.]]></summary></entry><entry><title type="html">Job change, lessons learned</title><link href="https://luca3m.me/2015/02/07/job-change-lessons-learned/" rel="alternate" type="text/html" title="Job change, lessons learned" /><published>2015-02-07T20:00:00+00:00</published><updated>2015-02-07T20:00:00+00:00</updated><id>https://luca3m.me/2015/02/07/job-change-lessons-learned</id><content type="html" xml:base="https://luca3m.me/2015/02/07/job-change-lessons-learned/"><![CDATA[<p>Last October I did one of the hardest decision of my life, I <strong>left my job</strong>.</p>

<p>It was my first experience, I joined that company for an internship and then I continued as a full-time engineer. They taught me what means beeing an engineer. I had a 9to5 job with a permanent position, some people may say they <em>have arrived</em>, what do you want more?</p>

<p>But after two years working there I started to be very stressed, every day I was losing the fun of what I was doing. I did a lot of amazing things, I have played a key role on a lot of core components of company platform. At a certain point, they gave me a task that made me very bored. I know that a job is not full of fun every day, you have to do things you love but also things you don’t like at all. So I said to myself: Luca, complete this task, the next will be more interesting. This was the motivation I used in past and worked well.</p>

<p>The task assigned went very bad, it was supposed to be a revolution for the platform but this time I failed, it didn’t work well. Then it was the time for holidays. Coming back home I was hoping that something changed, that I could go back to work with a good spirit and complete the task. But it was the same, as I have never been three weeks away. So I decided to  to <strong>quit</strong>, starting full-time looking for something new.</p>

<p>A very hard decision, but I felt inside myself that it was the correct one.</p>

<p>Some people did not understand my decision but I received a lot of congratulations for my choice by a lot of friends and my family. I was happy for having their support and I felt that everything would go well anyway.</p>

<p>So I started looking around, I spent my first day off sending CVs to all the world. The day after I received a lot of responses. Very great, it was a satisfaction. I took some time to work on my side projects, it was very amazing time.</p>

<p>I finally accepted an offer from a startup in Silicon Valley. Starting a new job isn’t easy. After you get acquainted in a job you feel very productive, I had a lot of knowledge and I was completing a lot of tasks everyday. When you start a new job you have to start again from scratch. Anything you say, it is wrong. And it’s very frustrating. Also I changed from a work shift of 8 hours from 9 to 6, to a job with free working hours. I can work whenever I like, from wherever I want, they didn’t care. Seems easy but it’s not. I suffered a lot staying at home all day too. It’s very difficult.</p>

<p>After some months I started to feel better and now I can say: yes, it was <strong>definitely</strong> the correct decision to make. Now I can make a summary of what I’ve learnt:</p>

<h2 id="learning-is-important">Learning is important</h2>

<p>On my previous job I was unhappy because I stopped learning. If you stop learning you start to get stressed. Doing new things, learn new things is one of the most important achievements that let you be happy of what you are doing.</p>

<h2 id="dont-fall-in-love">Don’t fall in love</h2>

<p>I enjoyed so much working with Redis, one of the smartest database I know. I felt that everything could be solved with it.
It’s wrong, if you do this mistake you are <strong>biased</strong> and you cannot do a good job. Different problems need different solutions. If you are not neutral, you may not do the right choice.</p>

<h2 id="focus-on-tasks-not-on-time">Focus on tasks, not on time</h2>

<p>Having free working hours is fantastic. It changes how you do your job, it’s more important what you do and not when. I suggest to keep a more or less 8 hours workday but split it however you want. For example I split a day in 15 pomodoros and my goal is to complete them more or less. During the morning I go to the swimming pool or spend lunch time with my girlfriend, anything; then I go back and work till I finish my day.</p>

<h2 id="break-your-shift">Break your shift</h2>

<p>I think that working everyday from office can be stressfull, daily commute can be very expensive in terms of money or time. But it’s important for team building. Working from home it’s very great, you have more time for you and more time to work. I think the best is to mix office work with home work, to have the best of both worlds.</p>

<h2 id="working-for-a-startup-is-amazing">Working for a startup is amazing</h2>

<p>There are different tradeoff between working for a big company or a startup. The former gives you bigger salary and a lot of benefits but you are just a pawn on a big game. The latter gives you more risk, less salary but more potential fame. On a startup you have a chance to play a <strong>key role</strong> for the success, and it’s very amazing.</p>]]></content><author><name>Luca Marturana</name></author><category term="english" /><summary type="html"><![CDATA[Last October I did one of the hardest decision of my life, I left my job.]]></summary></entry><entry><title type="html">Median filter with Redis</title><link href="https://luca3m.me/2014/05/27/median-filter-redis/" rel="alternate" type="text/html" title="Median filter with Redis" /><published>2014-05-27T20:56:00+00:00</published><updated>2014-05-27T20:56:00+00:00</updated><id>https://luca3m.me/2014/05/27/median-filter-redis</id><content type="html" xml:base="https://luca3m.me/2014/05/27/median-filter-redis/"><![CDATA[<p>Recently I had to implement a median filter algorithm, I found Redis very powerful
to accomplish this! A very simple solution and scalable.</p>

<p>As described in <a href="https://en.wikipedia.org/wiki/Median_filter">Wikipedia</a>, Median
filter works in this way: given a signal, output sample is the median of last N input
samples, where N can be any positive integer number. Higher is N, more aggressive
will be your filter.</p>

<p>We need a store for last samples, in a FIFO way, pushing a new one
will drop an older one. Redis provides <a href="https://redis.io/commands#list">lists</a>,
which are perfect for this scope. Also we need to sort these samples in numerical order, to get every
time we want the median value. Redis provides a
<a href="https://redis.io/commands/sort">SORT</a> command, which does this job.</p>

<p>I implemented these two primitives:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">add_sample(value)</code> - called every time to add a new sample</li>
  <li><code class="language-plaintext highlighter-rouge">get_median()</code> - to get the median value</li>
</ul>

<p>For the former we need to call two Redis commands:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MULTI
LPUSH &lt;yourkey&gt; &lt;value&gt;
LTRIM 0 &lt;N&gt;-1
EXEC
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">LPUSH</code> will simply add a new sample to the list, <code class="language-plaintext highlighter-rouge">LTRIM</code> ensures that at least
N elements will be stored, no more.</p>

<p>To get median value we need to call <code class="language-plaintext highlighter-rouge">SORT</code> and then calculate median. SORT returns
all values on that list, sorted by numerical order. I have preferred
to use a script, so Redis avoids returning non useful data to clients:</p>

<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">local</span> <span class="n">list_key</span> <span class="o">=</span> <span class="n">KEYS</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="c1">-- Key of samples list</span>

<span class="c1">-- Sort values</span>
<span class="kd">local</span> <span class="n">sorted_values</span> <span class="o">=</span> <span class="n">redis</span><span class="p">.</span><span class="n">call</span><span class="p">(</span><span class="s2">"SORT"</span><span class="p">,</span> <span class="n">list_key</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">size</span> <span class="o">=</span> <span class="o">#</span><span class="n">sorted_values</span>
<span class="kd">local</span> <span class="n">median</span> <span class="o">=</span> <span class="mi">0</span><span class="p">.</span><span class="mi">0</span>

<span class="c1">-- Calculate median</span>
<span class="k">if</span> <span class="n">size</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">then</span>
  <span class="n">median</span> <span class="o">=</span> <span class="p">(</span><span class="n">sorted_values</span><span class="p">[</span><span class="n">size</span><span class="o">/</span><span class="mi">2</span><span class="p">]</span><span class="o">+</span><span class="n">sorted_values</span><span class="p">[</span><span class="n">size</span><span class="o">/</span><span class="mi">2</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="mi">2</span>
<span class="k">else</span>
  <span class="n">median</span> <span class="o">=</span> <span class="n">sorted_values</span><span class="p">[(</span><span class="n">size</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">]</span>
<span class="k">end</span>
<span class="c1">-- Use tostring because median value may be floating point</span>
<span class="k">return</span> <span class="nb">tostring</span><span class="p">(</span><span class="n">median</span><span class="p">)</span>
</code></pre></div></div>

<p>Calling this script it’s easy:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>EVAL &lt;script&gt; 1 &lt;yourkey&gt;
</code></pre></div></div>

<p>Done!</p>]]></content><author><name>Luca Marturana</name></author><category term="english" /><summary type="html"><![CDATA[Recently I had to implement a median filter algorithm, I found Redis very powerful to accomplish this! A very simple solution and scalable.]]></summary></entry></feed>