<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Concepts on Post a Post</title><link>https://hernan941.com/en/categories/concepts/</link><description>Recent content in Concepts on Post a Post</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><managingEditor>hrwgallardo@gmail.com (Hernán)</managingEditor><webMaster>hrwgallardo@gmail.com (Hernán)</webMaster><copyright>Hernán Gallardo Palma (CC BY-NC 4.0)</copyright><lastBuildDate>Tue, 30 Jun 2026 11:00:00 -0300</lastBuildDate><atom:link href="https://hernan941.com/en/categories/concepts/index.xml" rel="self" type="application/rss+xml"/><item><title>I'm Using Claude Code</title><link>https://hernan941.com/en/posts/estoy-usando-claude/</link><pubDate>Tue, 30 Jun 2026 11:00:00 -0300</pubDate><author>hrwgallardo@gmail.com (Hernán)</author><guid>https://hernan941.com/en/posts/estoy-usando-claude/</guid><description>&lt;p&gt;For the last two months I&amp;rsquo;ve used Claude Code every day, shipping features from the terminal with zero shame, writing code powered by tokens and learning quite a bit along the way. I had already used agents for development before, Copilot in particular, but this time I took it to a completely different level of intensity.&lt;/p&gt;&#10;&lt;p&gt;The task and the goal was to be more productive, to be able to reach targets in impossible timeframes. To use modern technologies at a competitive pace without losing quality along the way, and without ceasing to build solid, scalable solutions. Do more with less. High cohesion and low coupling.&lt;/p&gt;</description><content:encoded><![CDATA[<p>For the last two months I&rsquo;ve used Claude Code every day, shipping features from the terminal with zero shame, writing code powered by tokens and learning quite a bit along the way. I had already used agents for development before, Copilot in particular, but this time I took it to a completely different level of intensity.</p>
<p>The task and the goal was to be more productive, to be able to reach targets in impossible timeframes. To use modern technologies at a competitive pace without losing quality along the way, and without ceasing to build solid, scalable solutions. Do more with less. High cohesion and low coupling.</p>
<p>On top of that, for my part, there was the challenge of keeping the attitude of the craftsman, the blacksmith, even when industrial machinery is at hand. A task that turns into a paradox: how to see beyond what merely &ldquo;works&rdquo; thanks to sheer mass production and keep the passion for the craft. How to transfer this intrinsic concern for the work to a stochastic model.</p>
<p><img src="https://dojiw2m9tvv09.cloudfront.net/29535/product/img_90495118.jpg" alt="Illustration of the blacksmith"></p>
<h1 id="first-month">First month</h1>
<p>To resolve this paradox, in the first few weeks I had to learn in detail what I was dealing with. And maybe this is the best moment to get into the subject and tell you about Claude Code. A programming agent used through the terminal, which has access to different actions inside your computer.</p>
<p>At its core, &ldquo;Claudito&rdquo; works with the concept of context. Imagine a room with defined walls and square meters, where light comes in, along with the furniture, table and chairs, people and pets: like a finite space of information that gives meaning and limits to our reality. And this is important: you have to keep in mind the limitations and how many things fit in the room. The context must contain everything needed for the solutions Claude delivers to be valid and accurate. MCPs, for example (the tools or extended functions, for instance to simulate a browser or access Google Drive), take up a significant amount of space in your context, and can leave you without enough room to give the agent the key background of the problem, inevitably making it lose track of the solution.</p>
<p>I started using it with these concepts in mind, the way its own creators suggest. A sequence of explore - plan - code - commit, but as the weeks went by I felt I was repeating my own flows. So I looked for the other ways people were using this tool. And I
discovered the concept of the harness and how to customize it.</p>
<h1 id="second-month">Second month</h1>
<p>The harness comes by default, and although it isn&rsquo;t the most optimal for every problem or technology, it works. The agentic harness is defined as the set of tools, context management and execution environment that turns a language model into an agent.</p>
<p>In other words, it could be translated as the harness that holds a climber on the mountain. In climbing (unless it&rsquo;s free solo), you need gear. Otherwise, you have nothing to hold on to; you have no protection. The harness is the safety equipment that connects you to the mountain. It gives you the ability to act, to be there and to move forward. And what better than having your own tools and adjusting them day by day.</p>
<p><img src="https://images.unsplash.com/photo-1684055301990-08b447719a89?q=80&amp;w=900&amp;auto=format&amp;fit=crop&amp;ixlib=rb-4.1.0&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="Climber on the mountain"></p>
<p>Without this, the solution takes a bit longer, or you find yourself telling it the same things over and over. So, from the second month on, I added dedicated skills and commands for the patterns and technologies I use, taking inspiration from a repository (ECC, winner of Anthropic&rsquo;s hackathon). All of this always implemented from a TDD (Test-Driven Development) perspective from day one. Tests here are vital, both to validate your code and to serve as a path for the models to understand it as the solution keeps growing. They are path and validation. Having the right patterns in every new plan secures my solution, but it isn&rsquo;t free: there is a context and token cost attached to every plan. Although, in my opinion, it&rsquo;s completely worth it.</p>
<p>And to make this harness work without running out of space, I leaned on persistent context, or memory. Since the session space is limited, per project you can have a CLAUDE.md file and various other .md files. These work as a usage guide; base instructions that Claude reads when starting inside a folder so it knows, beforehand, what the rules of your project are. The interplay between context and these files when working with Claudito also makes the difference.</p>
<h1 id="in-my-opinion">In my opinion</h1>
<p>With these techniques, Claude has become a snowball of productivity. It&rsquo;s what it promises: things that once took me weeks now take me a couple of minutes. Analyses that might take me months, Claude solves in one well-run session with the right questions. It&rsquo;s hard to look competitive in this industry without Claude as a copilot. Now, Claude doesn&rsquo;t get distracted and doesn&rsquo;t doubt. And it&rsquo;s at your command like an army of one. Army of one.</p>
<p>I know I can still apply techniques to reduce token spend, and even use that crazy learning skill where Claude recognizes my workflows. I dream of the day when you just talk to the computer and interact with a machine of peculiar personality; as of today, this is the closest thing to what I once imagined. And I also know how different Claude is working on existing code and its tendency to create rather than maintain. That its way of maintaining is adding and adding code. That it has strong preferences and that if you get careless you end up creating a swarm. Its swarm, one you don&rsquo;t understand. So my advice is to be careful and always keep understanding the moves toward the summit.</p>
<p>On the other hand, and with all that said, it&rsquo;s hard to keep seeing myself as the craftsman forging the rings of power, devoted to one single, specific and spectacular task. The day-to-day shifted more toward that of a strategist, drawing routes and plans, swapping weapon types and pulling the king&rsquo;s tokens as if it were war. Using the terminal and writing natural language to get what I want instead of flowing through logic gates.</p>
<table>
	<thead>
			<tr>
					<th style="text-align: center"><img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSM2p9ATlvf-1LcnPTn4c3W2iOPLE0OXI204NL5I_06wQ&amp;s=10" alt="Visual closing of the article"></th>
			</tr>
	</thead>
	<tbody>
	</tbody>
</table>
]]></content:encoded></item><item><title>Docker 101: containers, kernel and layers</title><link>https://hernan941.com/en/posts/docker101/</link><pubDate>Tue, 31 Mar 2026 11:00:00 -0300</pubDate><author>hrwgallardo@gmail.com (Hernán)</author><guid>https://hernan941.com/en/posts/docker101/</guid><description>&lt;p&gt;If you&amp;rsquo;re in the software world, chances are you&amp;rsquo;ve used Docker. And if not, here&amp;rsquo;s a definition:&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;Docker is a platform for developing, packaging and running containers. Important word: containers, which are isolated environments that include everything your software needs to work. These containers are created from images, immutable and reusable templates defined through a Dockerfile. Thanks to this, the same image can be used in development, testing and production, becoming a consistent unit of work in a distributed world.&lt;/p&gt;&#10;&lt;p&gt;There are also other concepts that tend to be overlooked: volumes, which let you persist data, and networks, which connect containers to each other. All of this within an ecosystem like Docker Hub, which offers thousands of ready-to-use images.&lt;/p&gt;&#10;&lt;/blockquote&gt;</description><content:encoded><![CDATA[<p>If you&rsquo;re in the software world, chances are you&rsquo;ve used Docker. And if not, here&rsquo;s a definition:</p>
<blockquote>
<p>Docker is a platform for developing, packaging and running containers. Important word: containers, which are isolated environments that include everything your software needs to work. These containers are created from images, immutable and reusable templates defined through a Dockerfile. Thanks to this, the same image can be used in development, testing and production, becoming a consistent unit of work in a distributed world.</p>
<p>There are also other concepts that tend to be overlooked: volumes, which let you persist data, and networks, which connect containers to each other. All of this within an ecosystem like Docker Hub, which offers thousands of ready-to-use images.</p>
</blockquote>
<p>I think knowing that, you could already start working and integrating containers into your workflow. But we don&rsquo;t stop here, let&rsquo;s go a little further.</p>
<p><img src="https://unsplash.com/photos/P6WRariZ-8M/download?force=true&amp;w=1600" alt="Whale tail emerging from the ocean"></p>
<h2 id="before-the-whales">Before the whales</h2>
<p>Before Docker there were virtual machines (VMs), which are, in essence, a complete emulation of a physical computer inside another one. Each VM acts as an independent machine, with its own virtual CPU, RAM and storage, which lets you run operating systems and applications in an isolated and secure way.</p>
<p>We could ask ourselves: why not keep using virtual machines? But there&rsquo;s an architectural drawback: the weight and volume of the box exceed those of its contents; that is, the system is wasting resources.</p>
<p>Each instance has to load and run a full operating system (Ubuntu, Debian, Windows or another), which takes a lot of resources. VM disk images usually take up gigabytes, and the boot process can take several minutes, even for simple applications. This creates overhead that affects both performance and system efficiency.</p>
<h2 id="using-the-kernel">Using the kernel</h2>
<p>Containers, unlike VMs, don&rsquo;t emulate a complete computer or require a separate operating system. Instead, they share the host operating system&rsquo;s kernel and isolate only the processes and resources needed to run an application. It&rsquo;s operating-system-level virtualization. This removes much of the overhead, allowing more efficient use of resources and near-instant deployment.</p>
<p>A good way to picture it is to imagine a VM as a detached house: it has its own foundations, pillars, electrical system and plumbing. Containers, on the other hand, are like apartments in a modern building. Each apartment shares the main structure, the electrical system and the plumbing. And yet each apartment has everything it needs to live comfortably and independently.</p>
<p><img src="https://unsplash.com/photos/XpyRouTu6NY/download?force=true&amp;w=1600" alt="Blue Building"></p>
<p>Thanks to this we get Docker&rsquo;s key values, particularly efficiency and resource optimization versus virtual machines:</p>
<ul>
<li>Portability: it works everywhere.</li>
<li>Efficiency and resource optimization: lots of containers.</li>
<li>Isolation and standardization: unit of work.</li>
</ul>
<h2 id="namespaces-and-cgroups">Namespaces and cgroups</h2>
<p>Containers work on top of the kernel in an isolated way through two mechanisms: namespaces and cgroups.</p>
<p>A namespace abstracts global system resources so that processes believe they have their own isolated instance. Changes made to a resource are visible only to the processes that belong to the same namespace, remaining invisible to the rest.</p>
<p>Currently, the Linux kernel has 8 types:</p>
<table>
	<thead>
			<tr>
					<th>Namespace</th>
					<th>Resource it isolates</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>cgroup</td>
					<td>Root directory of control groups (cgroup).</td>
			</tr>
			<tr>
					<td>IPC</td>
					<td>Inter-process communication (System V IPC, POSIX message queues).</td>
			</tr>
			<tr>
					<td>Network</td>
					<td>Network devices, protocol stacks, ports, etc.</td>
			</tr>
			<tr>
					<td>Mount</td>
					<td>Filesystem mount points.</td>
			</tr>
			<tr>
					<td>PID</td>
					<td>Process IDs (lets a process be PID 1).</td>
			</tr>
			<tr>
					<td>Time</td>
					<td>Boot and monotonic clocks.</td>
			</tr>
			<tr>
					<td>User</td>
					<td>User and group IDs (lets you be root inside the namespace).</td>
			</tr>
			<tr>
					<td>UTS</td>
					<td>Hostname and NIS domain name.</td>
			</tr>
	</tbody>
</table>
<p>If namespaces decide what you can see, cgroups decide how much you can use.</p>
<p>Cgroups let you allocate system resources (CPU, memory, network bandwidth or a combination) among user-defined groups of tasks (processes). And they go further, letting you monitor the consumption of the configured groups, restrict access to certain resources or set limits. They even let us adjust limits and priorities dynamically. With these mechanisms we achieve isolation.</p>
<h2 id="docker-operates-on-immutable-layers">Docker operates on immutable layers</h2>
<p>An immutable layer is a set of read-only files that records a specific state change in the image. Since they can&rsquo;t be altered, Docker reuses them across multiple containers without duplicating disk space, guaranteeing that the environment is always identical and predictable (determinism). Any later modification doesn&rsquo;t edit the base layer, but generates a new one on top of it, protecting the integrity of the original source.</p>
<p>Working across layers is possible thanks to the concept of UnionFS. This engine takes folders in different layers and &ldquo;merges&rdquo; them virtually so they look like a traditional filesystem. This way we get immutable layers working in harmony, making it possible to spin up disposable infrastructure that is completely replicable.</p>
<p><img src="/images/layers.webp" alt="Docker immutable layers"></p>
<h2 id="communication-and-networking">Communication and networking</h2>
<p>The network namespace is what isolates the network. Each container operates as if it had its own network card and its own IP. Based on this, to connect containers we need a &ldquo;switch&rdquo;, a bridge that allows interaction, as if it were a physical network, creating virtual cabling through a subnet.</p>
<p>But there&rsquo;s a problem: IPs are ephemeral and, so we don&rsquo;t have to configure IPs all the time, the internal DNS server steps in, intercepting the request and returning the current IP, or rather the service name. These 3 mechanisms let us keep communication fast, secure and reliable.</p>
<h2 id="docker-and-its-friends">Docker and its friends</h2>
<p>However, Docker is just the unit of work. In modern professional applications (like those using Django or FastAPI), we rarely work with a single container; we usually need a database, a backend, a worker and a frontend working together. This is where Docker Compose comes in as the orchestra conductor. With a single configuration file, you can define a complete infrastructure for a digital product.</p>
<p>Other technologies like Kubernetes or Docker Swarm let us orchestrate at a larger scale.</p>
<p>With that, I think that&rsquo;s enough whales for one day, maybe for a week, maybe for a good while. I hope it taught you something, and remember that all of these technologies draw heavily from others like operating systems, virtualization and networking&hellip; and remember: if you&rsquo;re out there working with Docker, don&rsquo;t forget to create your <code>.dockerignore</code>.</p>
<p><img src="https://unsplash.com/photos/WeUIHNHbs6o/download?force=true&amp;w=1920" alt="More whales"></p>
<hr>
<p><strong>Note:</strong></p>
<p>Docker Compose is great for development and testing, but in production you shouldn&rsquo;t put the database in a container. A database needs real persistence, high availability and good performance tuning. For production, it&rsquo;s safer to use managed services (AWS RDS, Cloud SQL) or dedicated VMs with backups, replicas and serious monitoring.</p>
<hr>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="https://github.com/ivanmorenoj/how-containers-works">How containers works</a></li>
<li><a href="https://docs.docker.com/get-started/docker-concepts/building-images/understanding-image-layers/#additional-resources">Understanding image layers (Docker Docs)</a></li>
<li><a href="https://sehun.me/layers-of-docker-image101-bca5beead44">Layers of Docker image 101</a></li>
</ul>
]]></content:encoded></item><item><title>Transactions and Concurrency: what you should know</title><link>https://hernan941.com/en/posts/concurrencia/</link><pubDate>Mon, 23 Feb 2026 12:51:00 -0300</pubDate><author>hrwgallardo@gmail.com (Hernán)</author><guid>https://hernan941.com/en/posts/concurrencia/</guid><description>&lt;p&gt;There are concepts that make the difference between a junior and a senior software engineer. Concepts that would fill several books. Here I try to close that gap a little between what we know and how it all connects.&lt;/p&gt;&#10;&lt;p&gt;For the last few weeks I&amp;rsquo;ve been mulling over how operations and concurrency work. What guarantees that a critical operation won&amp;rsquo;t break the system?&lt;/p&gt;&#10;&lt;h2 id="transaction-fundamentals"&gt;Transaction Fundamentals&lt;/h2&gt;&#10;&lt;p&gt;Nothing. There is no configuration that&amp;rsquo;s right for every case. What does exist is understanding how transaction states behave when they work together. A transaction is a consistency contract. When we don&amp;rsquo;t understand what happens at the levels below, we leave the system&amp;rsquo;s integrity to chance.&lt;/p&gt;</description><content:encoded><![CDATA[<p>There are concepts that make the difference between a junior and a senior software engineer. Concepts that would fill several books. Here I try to close that gap a little between what we know and how it all connects.</p>
<p>For the last few weeks I&rsquo;ve been mulling over how operations and concurrency work. What guarantees that a critical operation won&rsquo;t break the system?</p>
<h2 id="transaction-fundamentals">Transaction Fundamentals</h2>
<p>Nothing. There is no configuration that&rsquo;s right for every case. What does exist is understanding how transaction states behave when they work together. A transaction is a consistency contract. When we don&rsquo;t understand what happens at the levels below, we leave the system&rsquo;s integrity to chance.</p>
<p>This becomes obvious when we have to work on financial services, cryptocurrencies, inventory management, reservations or distributed systems.</p>
<h2 id="acid-transactions">ACID Transactions</h2>
<p>When databases started being used in critical systems, failures left data in inconsistent states, causing costly errors. In the 80s, Jim Gray and other researchers defined the ACID properties: Atomicity, Consistency, Isolation and Durability. Four rules that guarantee that, even in the face of failures, data stays correct.</p>
<h4 id="atomicity">Atomicity</h4>
<p>It&rsquo;s the &ldquo;all or nothing&rdquo; idea. A transaction can have 10 steps, but if step 9 fails, the other 8 are undone as if they had never existed. This is achieved through logs (Write-Ahead Logging).  The database writes down what it&rsquo;s going to do before touching the actual data. If there&rsquo;s an error, it uses that log to apply a Rollback and return to the initial state.</p>
<h4 id="consistency">Consistency</h4>
<p>It guarantees that a transaction only takes the database from one valid state to another. The core of this property is enforcing business rules. The tools involved are Triggers, Foreign Keys, Check Constraints and data types. For example. If you try to set a negative volume and there&rsquo;s a rule forbidding it, the transaction bounces.</p>
<h4 id="isolation">Isolation</h4>
<p>This is where things get interesting. When several transactions try to access and modify the same resource at the same time, they can&rsquo;t simply run in parallel without coordination. If they did, we&rsquo;d end up with inconsistent states. That&rsquo;s why a transaction has to wait its turn while another one finishes its operation on that same data.</p>
<p>Concurrency happens when the execution of two or more pieces of code behaves as if they were running at the same time.</p>
<p>To deal with concurrency, coordination is achieved with mutual exclusion primitives. At a low level we&rsquo;re talking about mutexes: mechanisms that guarantee that only one thread or process accesses a critical resource at a time (<a href="https://www.youtube.com/watch?v=1tZhmTnk-vc">if you want to know more</a>). In databases, the concept translates into locks, which apply that exclusion on rows, pages or tables. It&rsquo;s not optional cooperation; the engine enforces these rules to protect integrity.</p>
<table>
	<thead>
			<tr>
					<th>Locking Type</th>
					<th>Description</th>
					<th>Characteristics</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Pessimistic Locking 🙁</td>
					<td>&ldquo;I put a lock on the data until I&rsquo;m done&rdquo;</td>
					<td>Nobody else touches anything. It&rsquo;s safe but slow.</td>
			</tr>
			<tr>
					<td>Optimistic Locking 🙂</td>
					<td>&ldquo;I don&rsquo;t lock, I assume nobody else will touch it&rdquo;</td>
					<td>At the end, I check whether someone changed something. If someone did, I abort and retry. It&rsquo;s much faster for high-traffic systems.</td>
			</tr>
	</tbody>
</table>
<p>Now then, when and how are these locks applied? That&rsquo;s where <strong>isolation levels</strong> come in: settings that define how strict the database will be when applying locks between concurrent transactions. Each level makes different trade-offs between consistency and performance:</p>
<table>
	<thead>
			<tr>
					<th>Level</th>
					<th>Description</th>
					<th>Characteristics</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Read Uncommitted</td>
					<td>The &ldquo;Wild West&rdquo;</td>
					<td>A transaction can see changes from another one that haven&rsquo;t been committed yet. Risk: Dirty reads.</td>
			</tr>
			<tr>
					<td>Read Committed</td>
					<td>PostgreSQL&rsquo;s default</td>
					<td>You can only read data that has already been committed (Committed).</td>
			</tr>
			<tr>
					<td>Repeatable Read</td>
					<td>Prevents non-repeatable reads</td>
					<td>Guarantees that if you read a record twice in the same transaction, you&rsquo;ll see the same thing, even if someone else modified it in between.</td>
			</tr>
			<tr>
					<td>Serializable</td>
					<td>Maximum safety level</td>
					<td>Transactions run as if they were standing in a single-file line, one after another, even though they happen in parallel. It&rsquo;s the safest but the slowest.</td>
			</tr>
	</tbody>
</table>
<h4 id="durability">Durability</h4>
<p>It&rsquo;s the promise that, once the system tells you &ldquo;OK, saved&rdquo;, that information won&rsquo;t be lost even if the power goes out or the server blows up right afterwards.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/en/thumb/1/11/Disaster_Girl.jpg/250px-Disaster_Girl.jpg" alt="Disaster Girl"></p>
<p>Changes are written to non-volatile storage (hard drive/SSD) and confirmed in the transaction log. Even after a catastrophic failure, on restart the database reads the log and finishes applying whatever was left pending.</p>
<h2 id="beyond-acid">Beyond ACID</h2>
<p>Nowadays, these concepts are the foundation of relational databases. However, understanding this is just the first step. When you make the jump to modern architectures with microservices and NoSQL databases, the engine can no longer guarantee ACID across the whole system, because your data now lives on separate servers and the rules of the game change.</p>
<p>When distributing information, ACID&rsquo;s rigidity is often traded for a more flexible approach that prioritizes the system never going down. We call this new paradigm BASE:</p>
<table>
	<thead>
			<tr>
					<th>BASE Property</th>
					<th>Description</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>B</strong>asically Available</td>
					<td>The system guarantees it will always respond to requests, even if some nodes or servers fail.</td>
			</tr>
			<tr>
					<td><strong>S</strong>oft state</td>
					<td>Since data is being synchronized between servers, the system&rsquo;s state can change over time, even if there are no new write operations.</td>
			</tr>
			<tr>
					<td><strong>E</strong>ventual consistency</td>
					<td>The promise that, if we stop sending changes and wait long enough, all servers will eventually have the same version of the data.</td>
			</tr>
	</tbody>
</table>
<p>Going from ACID to BASE means accepting that your system will live with some temporary inconsistency in exchange for being incredibly fast and resilient to massive outages. At this point data integrity stops coming from the engine&rsquo;s configuration and becomes design patterns you have to implement in code (like the Saga pattern or Two-Phase Commit) to tie up the loose ends.</p>
<p>But that&hellip; is a story for another post.</p>
]]></content:encoded></item></channel></rss>