<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juan Miguel Rodriguez Ceron</title>
    <description>The latest articles on DEV Community by Juan Miguel Rodriguez Ceron (@juanmirod).</description>
    <link>https://dev.to/juanmirod</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F31838%2F91718722-cb17-44d1-86c1-ef2eb4950fe9.png</url>
      <title>DEV Community: Juan Miguel Rodriguez Ceron</title>
      <link>https://dev.to/juanmirod</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juanmirod"/>
    <language>en</language>
    <item>
      <title>Claude Code Sub-Agents: Orchestration Patterns That Scale (Without the Burnout)</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Fri, 07 Aug 2026 15:19:33 +0000</pubDate>
      <link>https://dev.to/juanmirod/advanced-claude-code-orchestration-sub-agents-and-not-burning-out-1bko</link>
      <guid>https://dev.to/juanmirod/advanced-claude-code-orchestration-sub-agents-and-not-burning-out-1bko</guid>
      <description>&lt;p&gt;A few days ago I gave an internal talk at Clarity's AI tools Community of Practice about advanced Claude Code usage. It was a live demo, so this is the written, tidied-up version of what I showed, for anyone who wants to come back to it.&lt;/p&gt;

&lt;p&gt;This is the companion post to &lt;a href="https://dev.to/juanmirod/pi-a-minimal-agent-harness-5c5i"&gt;Pi: a Minimal Agent Harness&lt;/a&gt;: if that one is about the smallest possible tool and everything you learn because it hides nothing, this one is about squeezing a very complete one for all it's worth.&lt;/p&gt;

&lt;p&gt;One heads-up before we start: this is &lt;strong&gt;advanced content&lt;/strong&gt;. It assumes you're already comfortable running Claude in auto mode — that is, you trust the agent enough to let it execute without approving every step. If you're just starting out, do the basic path first — plan mode, iterate, review — and come back later. I say this because almost everything that follows takes that trust for granted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The normal flow is still 90% of it
&lt;/h2&gt;

&lt;p&gt;Before the flashy stuff, it's worth remembering that the most common flow is still "the usual one", and it's the foundation of everything else:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Describe the task in &lt;strong&gt;plan mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Iterate on the plan until it makes sense.&lt;/li&gt;
&lt;li&gt;Implement/execute the plan.&lt;/li&gt;
&lt;li&gt;Review the changes.&lt;/li&gt;
&lt;li&gt;Open the MR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's literally 90% of the time. The one new rule worth internalizing: &lt;strong&gt;if you find yourself repeating the same instructions three or more times, turn them into a repo-specific skill.&lt;/strong&gt; That single habit gives you more leverage than anything else in this post. In the frontend repo we already have several skills (create MR, remove a feature toggle, remove warnings, debug), and the beauty is that they're adapted to the repo, so the agent already knows where to look and which tools to use without you explaining it every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Orchestrating agents: serial or parallel
&lt;/h2&gt;

&lt;p&gt;When a task doesn't fit in a single conversation, you can have Claude split it across several agents. There are many ways to orchestrate that, and picking the right one makes all the difference in control and cost. These are the two most basic models I've tried so far:&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;serial&lt;/strong&gt;: a resumable loop where you make one change, wait for its MR to be merged, and only then move on to the next. The state lives in a markdown file, so you can close your laptop and pick it up the next day. This is what you want when you have lots of similar changes but need to &lt;strong&gt;review each MR&lt;/strong&gt; before moving on. It's cheap, because only one task runs at a time, and although Claude does most of the work, a human stays in the loop the whole time.&lt;/p&gt;

&lt;p&gt;The second is &lt;strong&gt;parallel&lt;/strong&gt;: Claude launches &lt;strong&gt;many sub-agents at once&lt;/strong&gt; to do independent pieces simultaneously. It's for repetitive work with no ordering dependencies — adding return types to every file, increasing test coverage, migrations... — tasks where each sub-agent can work on its own on a file or module. You can ask Claude to orchestrate the sub-agents, have each one work in its own worktree or make its own commit, and let the main agent handle merging everything and opening the MR. It's much faster, but expensive in tokens. Each sub-agent is like an independent conversation, except this time between the orchestrator and the sub-agent, following the plan you defined earlier. To activate it, just ask with words like "fan out" or "spawn agents" when creating the plan: either one tells Opus to put together a parallel orchestration plan.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A tip that can genuinely save you money: &lt;strong&gt;explicitly tell it to use Sonnet for the sub-agents.&lt;/strong&gt; If you don't, it may end up running them with Opus or Fable and burn tokens at a terrifying rate (the classic case is Fable spending "like crazy"). The rule is: &lt;strong&gt;orchestrate with Opus, execute subtasks with Sonnet.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Commands worth knowing
&lt;/h2&gt;

&lt;p&gt;Beyond orchestration, there are a handful of commands I showed in the demo and use often:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep research.&lt;/strong&gt; Works like Perplexity or Google's deep search: it spawns agents in parallel, searches sources, and compiles a cited report. Very useful for researching new topics, exploring market alternatives, reviewing the literature on a specific problem... Watch the model again: Opus gets better results but costs more; Sonnet is cheaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handoff.&lt;/strong&gt; You ask Claude to write a plan in markdown with everything needed to continue in a new session. Perfect when you spot a refactor or subtask you don't want to cram into the current MR, or when you're about to run out of context. There's a &lt;a href="https://github.com/mattpocock/skills/blob/main/skills/productivity/handoff/SKILL.md" rel="noopener noreferrer"&gt;well-known skill&lt;/a&gt; for this, but it's really four lines: you can just ask Claude directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;/insights&lt;/code&gt;.&lt;/strong&gt; Analyzes all your sessions and generates an HTML report with statistics, the problems you usually trip over, improvement suggestions, and even "moonshots". Great for debugging your own skills, hooks, and agents. Worth running every now and then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remote control.&lt;/strong&gt; Lets you monitor and pilot an active session from your phone or another browser, while the session keeps running in the terminal. It's &lt;a href="https://code.claude.com/docs/en/remote-control" rel="noopener noreferrer"&gt;documented here&lt;/a&gt;. It's a bit buggy — sometimes the connection drops and you have to go back to the terminal — but its real value is that it lets you &lt;strong&gt;get up from your chair&lt;/strong&gt;: approve a plan from the kitchen, go out for a walk. One warning, half legal, half health-related: don't use it outside working hours; in Spain that's literally illegal. Which ties into the next point, and this one is serious.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3nonyxh5pcfweea0a44k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3nonyxh5pcfweea0a44k.png" alt="Developer walking in the park while controlling Claude Code from their phone" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't burn out
&lt;/h2&gt;

&lt;p&gt;These flows are fast and highly addictive. Because they move so quickly, you &lt;em&gt;feel&lt;/em&gt; like stopping is losing money or time, and that keeps you glued to the screen. That's a recipe for burnout. Take breaks, stand up, and don't have five agents running all the time just because. This isn't a joke — there are plenty of testimonies about it, and if this was already a problem in the profession, it's going to get much worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  But how did we get here?
&lt;/h2&gt;

&lt;p&gt;If you stop to think about it, the leap is enormous. I've been writing about this on the blog for a few years, and rereading those posts is a bit dizzying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;a href="https://juanmirod.github.io/2023/04/16/trabajando-con-chat-gpt.html" rel="noopener noreferrer"&gt;&lt;em&gt;Developing with ChatGPT&lt;/em&gt;&lt;/a&gt; (April 2023) I told how I asked ChatGPT for code snippets and pasted them by hand, amazed that it would write me a decent Dockerfile or README.&lt;/li&gt;
&lt;li&gt;A year later, in &lt;a href="https://juanmirod.github.io/2023/11/02/llms-review.html" rel="noopener noreferrer"&gt;&lt;em&gt;LLMs review, one year on&lt;/em&gt;&lt;/a&gt;, things already looked like a paradigm shift, although still surrounded by skepticism and without a clear sense of where it was heading.&lt;/li&gt;
&lt;li&gt;And in &lt;a href="https://juanmirod.github.io/2026/01/14/augmented-codin-review.html" rel="noopener noreferrer"&gt;&lt;em&gt;2025 review in 'assisted' development&lt;/em&gt;&lt;/a&gt; (January this year) I was already talking about entire projects done in days instead of months, and about hand-writing code starting to make no sense.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In less than three years we've gone from copy-pasting snippets from a chat to orchestrating swarms of agents that open their own MRs while we review. What I describe in this post — orchestrating sub-agents, letting them run in auto mode, piloting them from your phone — would have sounded like science fiction when I wrote that first post. And I have a feeling that in a year this will also feel dated. That's why I think it's worth leaving these notes as a snapshot of where we are today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start
&lt;/h2&gt;

&lt;p&gt;If I had to pick three things to try this week:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Turn an instruction you repeat often into a skill&lt;/strong&gt;, in a repo you actually work on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run &lt;code&gt;/insights&lt;/code&gt; once&lt;/strong&gt; and adopt at least one of its suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrate a serial batch&lt;/strong&gt; over a small set of similar tickets, with sub-agents on Sonnet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As always, you can leave comments on github or write to me on &lt;a href="https://bsky.app/profile/juanmirod.bsky.social" rel="noopener noreferrer"&gt;bluesky&lt;/a&gt;. And if you set up your own agent orchestration, I'd love to hear how it went.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>claude</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Pi: The Minimal Agent Harness That Powers OpenClaw — Run It Safely in Docker</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Fri, 07 Aug 2026 15:01:26 +0000</pubDate>
      <link>https://dev.to/juanmirod/pi-a-minimal-agent-harness-5c5i</link>
      <guid>https://dev.to/juanmirod/pi-a-minimal-agent-harness-5c5i</guid>
      <description>&lt;p&gt;A few weeks ago I gave another internal talk, this time about &lt;a href="https://mariozechner.at/posts/2025-11-30-pi-coding-agent/" rel="noopener noreferrer"&gt;Pi&lt;/a&gt;, a coding agent harness I've been using to experiment. If the &lt;a href="https://juanmirod.github.io/2026/06/23/usos-avanzados-de-claude-code.html" rel="noopener noreferrer"&gt;Claude Code post&lt;/a&gt; was about squeezing a very complete tool, this one is almost the opposite: the smallest possible tool, and everything you can learn precisely because it hides nothing.&lt;/p&gt;

&lt;p&gt;Heads-up: this is experimental territory, not a recommendation for your daily workflow. Pi is powerful and dangerous in equal measure, and part of the fun of this post is giving you a template so you can play with it without shooting yourself in the foot.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Pi is
&lt;/h1&gt;

&lt;p&gt;Pi is the agent harness that actually sits at the core of OpenClaw. It's minimal to the extreme: &lt;strong&gt;four tools&lt;/strong&gt; — &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;write&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;ls&lt;/code&gt; — and with that, a model can do anything on a computer. No plan mode, no MCPs, no sub-agents, no Jira integration, no connection to your GitHub repo. Above all, there's &lt;strong&gt;no permissions system and no guardrails&lt;/strong&gt;: you ask it for something and it goes and does it, doing whatever is needed to get it done, including installing global dependencies or writing bash scripts.&lt;/p&gt;

&lt;p&gt;My favorite metaphor: &lt;strong&gt;Pi is to agent harnesses what vim is to IDEs.&lt;/strong&gt; It's the bare minimum, and you can add whatever you want on top. Just like you can build your own IDE on top of vim, you can build your own Claude Code on top of Pi.&lt;/p&gt;

&lt;p&gt;Minimal as it is, it's not without opinions. It has three very specific traits that make it interesting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transparency.&lt;/strong&gt; The model's entire thought process, every tool call, every command and its output are visible in the session output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session export.&lt;/strong&gt; It generates an HTML file with the complete session that you can share.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree navigation.&lt;/strong&gt; You can jump to any point, resume the session from there, and open a new branch in the session tree.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Why transparency matters so much
&lt;/h1&gt;

&lt;p&gt;This is what really hooked me. When you work with Claude Code and spawn sub-agents, all you see is "working…" and then a result; with the new versions you can jump into the sub-agent's session, but all of that is lost once the agent finishes its work. With Pi you see &lt;strong&gt;exactly&lt;/strong&gt; what the model is doing at every step. If you want sub-agents, you ask pi to create them using pi, in tmux or as background processes — and you can save those sessions too.&lt;/p&gt;

&lt;p&gt;The HTML export lets you review everything with a small UI: a sidebar with navigation where you can filter to only the user prompts, see everything with or without tool calls, and jump to any point. (Claude's export, by comparison, is the bare console text.)&lt;/p&gt;

&lt;p&gt;What's that good for in practice? &lt;strong&gt;Learning how a model behaves&lt;/strong&gt; given a specific prompt. Whether the model gets something wrong or tries several times, whether it starts "reading" files it shouldn't, whether it misinterprets your prompt (you also see the full "thinking" output).&lt;/p&gt;

&lt;p&gt;I ran the same task — replacing some percentages with bars in a dashboard — with Claude using Opus and with Pi using an open-source model, and comparing the two sessions side by side was the most instructive part of the whole experiment: where it needs an example, where it forgets to write tests (both forgot, by the way).&lt;/p&gt;

&lt;h1&gt;
  
  
  Running it safely
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Pi runs in YOLO mode by default.&lt;/strong&gt; No permission prompts, no questions, it does what it thinks it needs to do. Installing it globally on your machine is &lt;strong&gt;very risky and totally inadvisable&lt;/strong&gt; — one bad prompt or one hallucination and you have the agent running &lt;code&gt;bash&lt;/code&gt; with your credentials and your whole filesystem within reach.&lt;/p&gt;

&lt;p&gt;One solution is to put it in a Docker container. For the agent, the whole world is that empty container with a project folder and nothing else. It doesn't see your environment variables (only the ones you pass), doesn't see your system, and can't touch the network unless you explicitly allow it. The risk of it doing something destructive drops massively.&lt;/p&gt;

&lt;p&gt;You can use this Dockerfile as a template: it installs &lt;code&gt;pi&lt;/code&gt; globally, copies your provider extension if you use LiteLLM or ollama, and gets everything ready to run as an unprivileged user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:24-bookworm-slim&lt;/span&gt;

&lt;span class="c"&gt;# Basic tools + pi installed globally&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; git ripgrep fd-find &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /usr/bin/fdfind /usr/local/bin/fd
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @mariozechner/pi-coding-agent

&lt;span class="c"&gt;# Pi config structure under the node user's home&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/node/.pi/agent/extensions &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; node:node /home/node/.pi

&lt;span class="c"&gt;# Pass whatever config you want, like your provider extension,&lt;/span&gt;
&lt;span class="c"&gt;# your settings and the model list&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=node:node extensions/ /home/node/.pi/agent/extensions/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=node:node .pi/settings.json /home/node/.pi/agent/settings.json&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --chown=node:node .pi/agent/models.json /home/node/.pi/agent/models.json&lt;/span&gt;

&lt;span class="c"&gt;# Non-root user (UID 1000): no sudo, and files keep your permissions&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; node&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /workspace&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["pi"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build it with &lt;code&gt;docker build -t pi-agent .&lt;/code&gt; and, once you have the image, run it interactively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cap-drop&lt;/span&gt; ALL &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--security-opt&lt;/span&gt; no-new-privileges &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$YOUR_API_KEY&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/workspace"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  pi-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--cap-drop ALL&lt;/code&gt; removes all Linux capabilities and &lt;code&gt;--security-opt no-new-privileges&lt;/code&gt; prevents privilege escalation inside the container.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;Dockerfile&lt;/code&gt; the agent runs as the &lt;code&gt;node&lt;/code&gt; user (UID 1000, not root), so it has no sudo and the files it creates have user 1000 permissions — usually the first user on the system, so it probably matches yours.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v "$(pwd):/workspace"&lt;/code&gt; mounts only the current directory: the only thing the agent can read, edit or execute.&lt;/li&gt;
&lt;li&gt;Only the environment variables you pass with &lt;code&gt;-e&lt;/code&gt; reach it, normally nothing more than the API key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One detail worth mentioning: I put an &lt;code&gt;AGENTS.md&lt;/code&gt; in the image telling the agent it's inside an isolated sandbox, that it should &lt;strong&gt;not&lt;/strong&gt; try to inspect the environment (DNS, installed tools, network…) because what it sees doesn't correspond to your real machine, and that it should instead give you instructions so you can check things yourself. Without that, small models start running &lt;code&gt;dig&lt;/code&gt; and &lt;code&gt;whois&lt;/code&gt; inside the container and confuse themselves.&lt;/p&gt;

&lt;p&gt;With an alias you're two keystrokes away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;pi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'docker run -it --cap-drop ALL --security-opt no-new-privileges -e API_KEY=$YOUR_API_KEY -v "$(pwd):/workspace" pi-agent'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy as &lt;code&gt;pi&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Models: from cloud proxies to open source
&lt;/h1&gt;

&lt;p&gt;Pi talks to any OpenAI-compatible provider, and adding one is a few lines in an extension. The structure looks like this (you register a provider with its &lt;code&gt;baseUrl&lt;/code&gt;, its key and the model list):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ExtensionAPI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@mariozechner/pi-coding-agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExtensionAPI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://your-litellm-proxy/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai-completions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;glm-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GLM 5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;contextWindow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cacheRead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cacheWrite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// ...more models&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pointing at a proxy like LiteLLM you can use both frontier models (Claude and friends) and open-weight ones, which is where the fun part is. Of what I've tried, &lt;strong&gt;GLM 5 is the best by far&lt;/strong&gt; — I'd say it's around Sonnet level — and you can do a lot with it; Minimax 2.5 and Kimi K2.5 also hold up well. I wouldn't use it for everything (you miss the MCPs, integrations, memory, sub-agents…), but running them a couple of times while watching the whole session teaches you a lot about where open models stand today.&lt;/p&gt;

&lt;h1&gt;
  
  
  Local models with Ollama
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8n3azb0v1yg0sklwsmyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8n3azb0v1yg0sklwsmyk.png" alt="Pi running with a local model" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another option is running the model &lt;strong&gt;on your own machine&lt;/strong&gt;, without sending anything anywhere. Pi connects to &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; just like any other OpenAI-compatible provider (pointing at &lt;code&gt;http://127.0.0.1:11434/v1&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Using an Ollama model for agentic tasks isn't entirely plug-and-play: you need to create a variant with the right configuration using a &lt;code&gt;Modelfile&lt;/code&gt;. The key is &lt;strong&gt;lowering the temperature and tuning the context window and output tokens&lt;/strong&gt;. The Gemma4 models have their own recommended parameters for agentic tasks; for qwen I've tested with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM qwen3.5:9b

# Config for coding tasks: low temperature, contained context
PARAMETER temperature 0.1
PARAMETER top_p 0.8
PARAMETER top_k 20

PARAMETER num_ctx 32768
PARAMETER num_predict 4096

# Number of CPUs (leave headroom to keep working)
PARAMETER num_thread 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull qwen3.5:9b
ollama create qwen-coding &lt;span class="nt"&gt;-f&lt;/span&gt; Modelfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On which model to choose, my experience on a Linux box with 32 GB of RAM and &lt;strong&gt;no GPU&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;9B&lt;/strong&gt; (Qwen) is the reasonable minimum. It takes over a minute to warm up and is slow, but it handles small tasks and answers questions about the repo.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;4B&lt;/strong&gt; hallucinates out of control: it makes things up and keeps derailing the conversation.&lt;/li&gt;
&lt;li&gt;On a &lt;strong&gt;Mac&lt;/strong&gt;, you can go for 27/30B models, which land somewhere between Haiku and Sonnet in terms of capability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pi has one decisive advantage over Claude Code for small models: Claude Code's system prompt is thousands of lines with a ton of tools, and that &lt;strong&gt;overwhelms&lt;/strong&gt; small open models. Pi's minimalism is exactly what lets them work.&lt;/p&gt;

&lt;p&gt;There's something special about being offline — on a train or wherever — and still being able to ask your repo questions and get changes made by just asking the agent.&lt;/p&gt;

&lt;h1&gt;
  
  
  In summary
&lt;/h1&gt;

&lt;p&gt;Pi as a &lt;strong&gt;test bench&lt;/strong&gt; is unbeatable: you see everything the model does, compare behaviors, and can run open-source and local models that wouldn't even start under a heavier harness. If you're interested in understanding how agents work on the inside, instead of just using them, it's well worth setting it up over a weekend. Just make sure: &lt;strong&gt;inside a container&lt;/strong&gt;. If you're interested, I have a small &lt;a href="https://github.com/juanmirod/pi-agent" rel="noopener noreferrer"&gt;repo with this setup for local models on github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As always, you can leave comments here or on github or write to me on &lt;a href="https://bsky.app/profile/juanmirod.bsky.social" rel="noopener noreferrer"&gt;bluesky&lt;/a&gt;. And if you set up your own Pi configuration, I'd love to hear how it goes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>coding</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Using the Socratic method for mentoring</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Wed, 28 Jun 2023 21:04:47 +0000</pubDate>
      <link>https://dev.to/juanmirod/using-the-socratic-method-for-mentoring-l9l</link>
      <guid>https://dev.to/juanmirod/using-the-socratic-method-for-mentoring-l9l</guid>
      <description>&lt;p&gt;Using the Socratic method in the workplace can be a powerful tool for mentoring junior coworkers, guiding team meetings, and encouraging critical thinking and problem-solving skills.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h2jidTil--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/e/eb/Marcello_Bacciarelli_-_Alcibiades_Being_Taught_by_Socrates%252C_1776-77_crop.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h2jidTil--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://upload.wikimedia.org/wikipedia/commons/e/eb/Marcello_Bacciarelli_-_Alcibiades_Being_Taught_by_Socrates%252C_1776-77_crop.jpg" alt="Alcibiades Being Taught by Socrates, 1776-77" width="720" height="638"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://commons.wikimedia.org/wiki/File:Marcello_Bacciarelli_-_Alcibiades_Being_Taught_by_Socrates,_1776-77_crop.jpg"&gt;Marcello Bacciarelli&lt;/a&gt;, &lt;a href="https://creativecommons.org/licenses/by-sa/4.0"&gt;CC BY-SA 4.0&lt;/a&gt;, via Wikimedia Commons







&lt;p&gt;I specially like when a coworker or team lead challenges my opinion with &lt;strong&gt;the right question&lt;/strong&gt;, it makes me think about possible solutions instead of feeling attacked or contradicted. This is why I am trying to learn how to do it and apply it myself when I have the opportunity.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: The Socratic method is a very general term to describe the different techniques that Socrates used for teaching, encouraging critical thinking and discussion. In this post we will use it describe an approach about leading and mentoring at work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Socratic method involves asking open-ended questions that encourage coworkers to think deeply and critically&lt;/strong&gt; about the topic at hand, rather than simply telling them what to do. By giving them space to think and explore their own ideas, you'll be helping them become more confident and independent workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Socratic questioning effectively
&lt;/h2&gt;

&lt;p&gt;When using the Socratic method, it's important to &lt;strong&gt;actively listen to your coworker's responses and ask follow-up questions to clarify their thinking&lt;/strong&gt;. This will help you understand their thought process and guide them towards a deeper understanding of the topic. Additionally, it's important to demonstrate that you're actively listening and engaged in the conversation by maintaining eye contact, using nonverbal cues, summarizing key points, and avoiding interrupting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Ask open-ended questions that encourage deep and critical thinking&lt;/li&gt;
&lt;li&gt;Actively listen to coworker's responses and ask follow-up questions&lt;/li&gt;
&lt;li&gt;Demonstrate active listening and engagement through nonverbal cues and summarizing key points&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Example 1: Pairing
&lt;/h2&gt;

&lt;p&gt;As any other method or technique, knowing the theory is not enough, practicing is key to know which is the right question and when to do a new question or when to wait and give space to the other person. For example, this are some questions you could use while pairing or reviewing code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's your understanding of the problem we're trying to solve here?&lt;/li&gt;
&lt;li&gt;How would you approach this problem if you were working on it alone?&lt;/li&gt;
&lt;li&gt;What are some potential solutions you've considered so far?&lt;/li&gt;
&lt;li&gt;What are the pros and cons of each solution?&lt;/li&gt;
&lt;li&gt;How would you test your solution to make sure it works as expected?&lt;/li&gt;
&lt;li&gt;Are there any edge cases or potential issues we should consider?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try to use them when you are pairing or discussing a topic with a coworker or friend and observe how they react, if you surprised them or they feel that their opinion is important. Observe also yourself, asking this questions when you think that you know the right answer is difficult. Were you able to be patient while your mentee was trying to find the right words? Did you look calm and encouraging? Were you listening actively? &lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2: In team meetings
&lt;/h2&gt;

&lt;p&gt;In team meetings, it's important to encourage participation from all team members by creating a supportive and inclusive environment. Acknowledging the contributions of different team members and using visual aids to participate (like boards or post-its or any of the multiple virtual tools that we have for meetings) can help to create that collaborative environment.&lt;/p&gt;

&lt;p&gt;So, for example, if you have a board where every member of the team has to add an idea or a concern (maybe anonymously, depending on the topic) and then you read them aloud and comment each of them with the team, each team member will feel that they have been listened and they had the opportunity to express themselves.&lt;/p&gt;

&lt;p&gt;As a senior developer, it's important to participate in team meetings and contribute your expertise without dominating the conversation or imposing your point of view. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Asking questions, providing context, sharing examples, encouraging collaboration, being neutral, and listening actively&lt;/strong&gt; are all ways to participate without giving a direct opinion.&lt;/p&gt;

&lt;p&gt;So, if you are one of the seniors members of the team, maybe you should try to lead some meetings using these practices, or simply offer yourself to take notes and lead the meeting from there. The person taking notes can summarize aloud what it has been said and remember any commitment or follow up actions that have been discussed.&lt;/p&gt;

&lt;p&gt;Key points to remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encourage participation from all team members&lt;/li&gt;
&lt;li&gt;Listen actively and ask follow-up questions&lt;/li&gt;
&lt;li&gt;Summarize key points and ask for feedback&lt;/li&gt;
&lt;li&gt;Avoid dominating the conversation and encourage collaboration&lt;/li&gt;
&lt;li&gt;Keep an open mind and remain neutral&lt;/li&gt;
&lt;li&gt;Acknowledge contributions&lt;/li&gt;
&lt;li&gt;Use visual aids to encourage participation&lt;/li&gt;
&lt;li&gt;Follow up individually if needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using the Socratic method in the workplace can be a powerful tool for mentoring junior coworkers and guiding team meetings. You can help your team members become more confident and independent workers, and encourage the generation of new ideas and solutions as a team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn more!
&lt;/h3&gt;

&lt;p&gt;Some links to keep learning about the topic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Socratic_questioning"&gt;Socratic questioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hbr.org/2018/05/the-surprising-power-of-questions"&gt;Asking good questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;LinkedIn Learning has many videos and courses about active listening that can be great to learn by example, f.e. &lt;a href="https://www.linkedin.com/learning-login/share?account=216505570&amp;amp;forceAccount=false&amp;amp;redirect=https%3A%2F%2Fwww.linkedin.com%2Flearning%2Fcentered-communication-get-better-results-from-your-conversations%2Factive-listening%3Ftrk%3Dshare_video_url%26shareId%3DpbPDhe03R1q3Env1ZFsyww%253D%253D"&gt;this video about active listening&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post was created and edited by me with help of AI and Google, I was learning about the topic and I thought that it may be useful to share a summary on the topic.&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>meetings</category>
      <category>learninpublic</category>
    </item>
    <item>
      <title>Developing with ChatGPT</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Mon, 24 Apr 2023 08:55:24 +0000</pubDate>
      <link>https://dev.to/juanmirod/developing-with-chatgpt-2jfm</link>
      <guid>https://dev.to/juanmirod/developing-with-chatgpt-2jfm</guid>
      <description>&lt;p&gt;Are you curious about the possibilities of ChatGPT and how it can be used in your own projects? With the recent exciting advancements in language models and generative AI, there's never been a better time to dive in and start experimenting. In this blog post, I'll be sharing my own journey of developing a personal assistant using ChatGPT - from the challenges I faced to the solutions I discovered along the way.&lt;/p&gt;

&lt;p&gt;As someone who has been following the exciting advancements in language models, generative AIs, and artificial intelligence, I couldn't wait to dive into the world of ChatGPT. It represented a paradigm shift in the way we think about natural language processing.&lt;/p&gt;

&lt;p&gt;For me, it was a clear sign that I needed to start taking learning about these topics more seriously, so I embarked on a &lt;a href="https://github.com/juanmirod/chatgpt_cli"&gt;personal project&lt;/a&gt; to create my own personal assistant using ChatGPT. I wanted to experiment and learn at my own pace, without the constraints of a directed course.&lt;/p&gt;

&lt;p&gt;My ultimate goal was to develop an assistant that really knew me - one that would remember our previous conversations and run on my own personal computer. Even if I never quite achieve this lofty ambition, I knew that working on this project would be a fantastic way to immerse myself in the topic.&lt;/p&gt;

&lt;p&gt;To make things even more challenging, I decided to use Python - a language I wasn't particularly proficient in - and to always rely on ChatGPT instead of turning to Google or external documentation. This created a project that was not only challenging and exciting, but also incredibly meta. By using ChatGPT to develop tools that will ultimately replace it with my own personalized version.&lt;/p&gt;

&lt;p&gt;For now the experience is great. I develop new functionality very quickly, ChatGPT unlocks me very often and keeps me much more in the flow than having to read documentation or search Google and in general the feeling of speed and satisfaction is great. I also believe that this is because I'm using ChatGPT in the ideal scenario: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A new and small project, a command-line app, so adding functionality is very easy, you don't need frameworks or components or big architectures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In a language I don't master, ChatGPT is very useful to solve doubts, and the domain itself is ChatGPT's specialty. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Python is a language especially suitable for LLMs because it has less syntax and is dynamic. Properties that make it ideal for humans and LLMs because right now it's the closest thing we have to programming in natural language. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without all these factors, the usefulness of ChatGPT starts to degrade for me. In fact, at work I use it much less often, it's just harder to explain what I want than to do it myself. But that's why I think we will all end up with our own personal or company assistant who knows the ins and outs of our projects and can help us with more context... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zO7FBwbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdgjzlr75eczxhmj4vb5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zO7FBwbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdgjzlr75eczxhmj4vb5.jpg" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But let's get to the point, I'm going to list some examples of how I've used ChatGPT in this project and when I can I'll link to specific conversations about that topic that I had with ChatGPT. These are some things I've done with ChatGPT to work, not just to explore what it knows, learn or try to play or entertain myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Readme&lt;/strong&gt;: The first version of the Readme was written by ChatGPT, I edited it and have been expanding and improving it since then.&lt;a href="https://gist.github.com/juanmirod/fce0104af6714c7527fce54639706407"&gt;Read the conversation here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;: I asked ChatGPT for a dockerfile because to be honest I don't know the syntax by heart and I always end up copy-pasting. At first it gave me a completely functional dockerfile and the command to execute the assistant from the dockerfile. Then I edited it a bit to remove some things I didn't need and change the order of the commands a bit to better use docker's cache.&lt;a href="https://gist.github.com/juanmirod/7be1a16f017ea8798754870d1bcd7ffa"&gt;Conversation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TTS&lt;/strong&gt;: The assistant has a text-to-speech option so you can listen to its responses, although by default I have it disabled (it's faster to read and the code doesn't make sense to listen to). The first version was again its own, then I tried several voices and libraries, and in the end I settled on one that wasn't the one ChatGPT suggested.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upload conversation to a gist&lt;/strong&gt;. I also asked ChatGPT for the upload file, then I put the code into a function to use it from the app instead of as a script.&lt;a href="https://gist.github.com/juanmirod/8b6044b0071bdcc5cb0bbcf933b7a576"&gt;Conversation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Retrieve a conversation parsing the markdown file&lt;/strong&gt;. This is not integrated yet, but I've already played with ChatGPT and have the initial code that should make it possible.&lt;a href="https://gist.github.com/juanmirod/4f0e8687b4620831afb1446aed027b0c"&gt;Conversation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refactors&lt;/strong&gt;. I've done several refactors where I've given it a big function and asked it to split it into smaller functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt;. The first tests of the ChatGPT class were done by ChatGPT, and the ones for the actions module were done with copilot's help. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general ChatGPT has helped me throughout the process. from outlining solutions, consulting how libraries work, writing tests... The pattern is similar every time, and that's why I think it's especially useful if you don't master the language, because if you do, you'll take the same time or less to write it yourself. But if you don't know the available libraries and modules, asking ChatGPT how it would do it saves a lot of time in trial and error and research and reading documentation.&lt;/p&gt;

&lt;p&gt;Besides, for me this process is usually a rabbit hole: I start looking for a library to do X and there are 10's, and now I have to see which ones are more popular and why, and I want to see a little how they work... and when I realize it's been 2 hours and I haven't done anything. With ChatGPT all that process is much more immediate and fluid, even if I end up using another library or heavily editing or discarding its first solution. It keeps me more in the flow and more focused on the problem than all those websites full of ads and cookie popups, videos and other distractions. &lt;/p&gt;

&lt;p&gt;I'm sure I'm only scratching the surface here. LLMs seem to have a lot of potential at various levels, and little by little we'll be integrating them into IDEs and user interfaces, but even in this rudimentary form and without knowing very well what I'm doing I think I gain a lot of productivity and the development process is much less frustrating.&lt;/p&gt;

&lt;p&gt;Thanks a lot for reading, if you got this far please tell me what you think in the comments. Have you used ChatGPT for programming? Do you have a specific setup or workflow? I would love to know about it!&lt;/p&gt;




&lt;p&gt;This blog post was translated by ChatGPT from the original Spanish one which you can read &lt;a href="http://juanmirod.github.io/2023/04/16/trabajando-con-chat-gpt.html"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>python</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Introducción a Node.js</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Mon, 16 Jul 2018 22:06:13 +0000</pubDate>
      <link>https://dev.to/juanmirod/introduccin-a-nodejs-npj</link>
      <guid>https://dev.to/juanmirod/introduccin-a-nodejs-npj</guid>
      <description>&lt;p&gt;(Este post fue publicado inicialmente en mi blog, pásate para ver más contenido sobre desarrollo, javascript y tecnología: &lt;a href="http://juanmirod.github.io/"&gt;Por amor al código&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt; es un entorno de ejecución de JavaScript que utiliza el motor V8 de Google. La historia de JavaScript y de Node.js es curiosa porque casi parece que todo surgió por accidente. JavaScript es conocido por haber sido &lt;a href="http://juanmirod.github.io/public/javascript10days.pdf"&gt;diseñado en 10 días por Bredan Eich&lt;/a&gt; y por sus &lt;a href="https://www.destroyallsoftware.com/talks/wat"&gt;inconsistencias&lt;/a&gt;, pero aun así, se ha convertido en el el lenguaje de facto de la web. La imposición tecnológica de los navegadores, unido a la bajísima curva de aprendizaje han hecho de JavaScript el lenguaje con más crecimiento de los últimos tiempos. Herramientas como jQuery, Mootools y Backbone, Lodash, Angular, React... Han ido evolucionando la arquitectura de un lenguaje dinámico en principio carente de estructura. JS es en la actualidad uno de los lenguajes más utilizados y de mayor crecimiento. Con lo que era inevitable que los desarrolladores de JavaScript quisieran usar el lenguaje fuera de los navegadores. Como dice la Ley de Atwood:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any application that can be written in JavaScript, will eventually be written in JavaScript &lt;a href="https://blog.codinghorror.com/the-principle-of-least-power/"&gt;ver más&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antes de Node.js hubo varios intentos de establecer un entorno de ejecución para JavaScript fuera de los navegadores. Los programadores querían sacar JavaScript del corsé del navegador, querían poder hacer aplicaciones, modificar ficheros y acceder al hardware. Una historia muy entretenida sobre los inicios de Node.js y npm la cuenta el propio Issac Z. Schlueter (creador de npm) &lt;a href="http://blog.izs.me/post/157295170418/my-first-npm-publish"&gt;en su blog&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Node.JS y npm se convirtieron en el entorno de ejecución de JavaScript en el servidor. Ahora podemos utilizar el mismo lenguaje para desarrollar en el servidor y en el cliente en el caso del desarrollo web, aunque también hay gente usando Node para ioT, para robots, para herramientas de línea de comandos, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalación y el REPL
&lt;/h2&gt;

&lt;p&gt;Para instalar Node.js en Windows o en Mac, basta con ir a la página principal y descargar el instalador. Si usas Ubuntu, solo necesitamos un par de comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs

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

&lt;/div&gt;



&lt;p&gt;Si usas otra distribución de Linux, &lt;a href="https://nodejs.org/en/download/package-manager/#installing-node-js-via-package-manager"&gt;mira aquí&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez instalado podemos comprobar que la versión es la correcta (actualmente la versión LTS es la 6.x) escribiendo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
node -v


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

&lt;/div&gt;



&lt;p&gt;Para ejecutar el intérprete de Node, el REPL, simplemente escribimos el comando &lt;code&gt;node&lt;/code&gt; y el terminal pasará a ser una consola de JavaScript en la que podremos ejecutar nuestro código.&lt;/p&gt;

&lt;p&gt;El REPL (siglas del inglés Read Eval Print Loop) es una consola que ejecuta cada expresión en JavaScript que le demos y devuelve el resultado de la expresión inmediatamente. Por ejemplo si escribimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; 2 + 2
4

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;4&lt;/code&gt; es el resultado de la expresión &lt;code&gt;2 + 2&lt;/code&gt;, otro ejemplo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; console.log('Hola Mundo')
'Hola Mundo'
undefined

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

&lt;/div&gt;



&lt;p&gt;'Hola mundo' es la salida que produce &lt;code&gt;console.log('Hola Mundo')&lt;/code&gt; y &lt;code&gt;undefined&lt;/code&gt; es lo que devuelve la función. También podemos definir funciones y variables &lt;code&gt;globales&lt;/code&gt; que podremos usar a continuación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; var factorial  = function(x) {
...   if ( x &amp;lt;= 1 ) return x
...   return x * factorial(x-1)
... } 
undefined
&amp;gt; factorial(4)
24

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

&lt;/div&gt;



&lt;p&gt;En las versiones actuales de Node.js tenemos soporte de prácticamente la totalidad de la especificación de ES2015, con lo que podríamos escribir la función de arriba de otra forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; const factorial  = x =&amp;gt; ( x &amp;lt;= 1 ) ? x : x * factorial(x-1) 
undefined
&amp;gt; factorial(4)
24

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

&lt;/div&gt;



&lt;p&gt;El REPL es muy útil para probar pequeñas funciones y expresiones, yo cada vez lo utilizo más a menudo y los ejemplos de este blog suelen estar escritos de forma que sean fáciles de probar en el REPL. La ventaja de tener una respuesta inmediata a una duda de código es invaluable y normalmente no nos damos cuenta de eso hasta que lo probamos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Módulos y npm
&lt;/h2&gt;

&lt;p&gt;Node no es solo el REPL, también podemos ejecutar ficheros. Solo tenemos que crear un fichero con el código javascript que queramos ejecutar y pasárselo al comando &lt;code&gt;node&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
echo 'console.log("Hello Node")' &amp;gt; hello.js
node hello.js
// Hello Node

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

&lt;/div&gt;



&lt;p&gt;Cada fichero JavaScript es un módulo para Node.js y si queremos usar alguna función definida dentro del fichero primero tendremos que exportarla. Por ejemplo creemos el fichero &lt;code&gt;factorial.js&lt;/code&gt; con el siguiente contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const factorial = x =&amp;gt; ( x &amp;lt;= 1 ) ? x : x * factorial(x-1)

module.exports = factorial


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

&lt;/div&gt;



&lt;p&gt;Si ejecutamos ese fichero veremos que no pasa nada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
node factorial.js 


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

&lt;/div&gt;



&lt;p&gt;Nuestro módulo no hace nada a parte de definir una función y exportarla, pero desde el propio REPL o desde otro fichero Node.js podremos importar esta función y utilizarla:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; const factorial = require('./factorial.js')
&amp;gt; factorial(5)
120

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

&lt;/div&gt;



&lt;p&gt;¿Mola eh? Ya tenemos un mecanismo para escribir código, encapsularlo en módulos y ejecutarlo. Esta es la base del desarrollo en Node, tan sencillo como eso. &lt;/p&gt;

&lt;p&gt;Node trae una serie de módulos básicos que podemos utilizar a modo de &lt;a href="https://nodejs.org/dist/latest-v6.x/docs/api/"&gt;librería estandard&lt;/a&gt; Pero uno de los puntos fuertes de Node.js es el haberse mantenido flexible gracias a tener una librería estandar muy pequeña.&lt;/p&gt;

&lt;p&gt;Ese es también el punto fuerte de npm. &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt; es un repositorio centraliazdo de módulos para Node.js En la comunidad de Node.js y npm la filosofía también es la de módulos pequeños que hagan una sola cosa, parecido a lo que ocurre con los comandos de Unix. Esto hace el lenguaje más fácil de componer, reordenar y modificar y tiene un gran potencial. Ahora mismo npm es el repositorio con mayor número de módulos de código abierto de todos los lenguajes y su número sigue creciendo a mayor velocidad que todos los demás.&lt;/p&gt;

&lt;p&gt;npm se instala en nuestro sistema junto con Node.js y podemos usarlo para instalar cualquier paquete de forma global o local a nuestro proyecto. Un proyecto es simplemente una carpeta donde hemos ejecutado &lt;code&gt;npm init&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
mkdir hello
cd hello
npm init

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

&lt;/div&gt;



&lt;p&gt;Al ejecutar este comando el programa nos hará algunas preguntas sobre el proyecto y creará un fichero &lt;code&gt;package.json&lt;/code&gt; con la configuración mínima. Si solo queremos probar a instalar algunos paquetes podemos ejecutar &lt;code&gt;npm init -y&lt;/code&gt; para crear este fichero y npm usará la configuración mínima por defecto y el nombre de la carpeta como nombre del proyecto.&lt;/p&gt;

&lt;p&gt;Ahora podemos instalar cualquier paquete del registro ejecutando &lt;code&gt;npm install&lt;/code&gt; Por ejemplo podemos instalar &lt;a href="http://expressjs.com"&gt;expressjs&lt;/a&gt;, una serie de librerías para crear un servidor web:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
npm install --save express

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

&lt;/div&gt;



&lt;p&gt;El modificador &lt;code&gt;--save&lt;/code&gt; indica a npm que queremos que guarde esta dependencia en el fichero del proyecto. Con express instalado localmente, podemos crear nuestro fichero &lt;code&gt;index.js&lt;/code&gt; con este contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const express = require('express')
const app = express()

app.get('/', function (req, res) {
  res.send('Hola desde Node!')
})

app.listen(3000, function () {
  console.log('Servidor creado y escuchando en el puerto 3000!')
})


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

&lt;/div&gt;



&lt;p&gt;Y ejecutarlo en la consola:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
node index.js

Servidor creado y escuchando en el puerto 3000!

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

&lt;/div&gt;



&lt;p&gt;Si abres un navegador y vas a 'localhost:3000' verás el mensaje 'Hola desde Node!'&lt;/p&gt;

&lt;p&gt;Esas son las herramientas básicas de desarrollo en Node.js. Módulos, un entorno de ejecución, el repositorio central de npm y JavaScript. Con lo que sabes ya puedes ir a explorar un poco el registro de npm o la documentación de express y comenzar a desarrollar tu propio servidor web :D&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Great github threads</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Sat, 30 Jun 2018 22:26:44 +0000</pubDate>
      <link>https://dev.to/juanmirod/great-github-threads-4975</link>
      <guid>https://dev.to/juanmirod/great-github-threads-4975</guid>
      <description>

&lt;p&gt;My favourite part about Github are the discussions. Like Twitter, Github allows you to watch the comments and code of well known software developers and have a pick of their way of thinking. The code is interesting, but a lot of times the code lacks the &lt;em&gt;WHY&lt;/em&gt;. Why the team or the developer chose to use a pattern or a design or why a feature made it to a language or not.&lt;/p&gt;

&lt;p&gt;You can see how big projects evolved thanks to issues, commits and PRs, and you can even participate in the debates and of course in the code. Before Github, all this information was in projects' newsletters, forums, chats... The information was more difficult to find and it would last less.&lt;/p&gt;

&lt;p&gt;Below there are a list of some Github threads that I considered interesting and worth of bookmarking. All of them, except for the last one, are about JavaScript, because it is my main language right now. Do you know any other great Github threads? Issues, PRs or maybe a gist that created an good discussion? Please leave it in the comments, I really love learning from others' points of views and their arguments. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/promises-aplus/promises-spec/issues/94"&gt;Promises are not monads&lt;/a&gt; Promises could have been very different if it wasn't for some opinionated developers that really wanted them to be like they are. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/nodejs/CTC/issues/12"&gt;Promisify/awaitable in node&lt;/a&gt; Another one about promises and why the &lt;em&gt;promisify&lt;/em&gt; function was added to node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/facebook/immutable-js/issues/341"&gt;Immutable issue about typescript&lt;/a&gt; Discussion of ways of creating immutable data structures that work with typescript.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ngrx/store/issues/23"&gt;About ngrx/store and immutable.js&lt;/a&gt; Immutable.js has trade offs as any other library. Immutability is great, but in JavaScript it is not idiomatic and it creates some friction...&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gist.github.com/substack/68f8d502be42d5cd4942#gistcomment-1365101"&gt;Browserify and webpack&lt;/a&gt; Browserify can do most of what webpack does, and even more in some cases, great gist and good discussion about the two tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/sindresorhus/ama/issues/10#issuecomment-117766328"&gt;One line modules&lt;/a&gt; Sindre Sorhus about one line modules and why npm made the &lt;em&gt;"utils scripts"&lt;/em&gt; folders irrelevant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/nodejs/node/pull/4765"&gt;Node-chakracore&lt;/a&gt; About adding the Microsoft core for JavaScript into Node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/torvalds/linux/pull/17#issuecomment-5654674"&gt;Linus Torvalds being... Linus Torvalds&lt;/a&gt; The last pearl in the list is not about JavaScript and not about a great discussion. Sometimes github allows you to see the bad parts of software development too. Linus is famous for being rude and coarse, this is just one of the multiple examples.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


</description>
      <category>github</category>
      <category>discuss</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Generadores en JavaScript</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Wed, 27 Jun 2018 22:35:27 +0000</pubDate>
      <link>https://dev.to/juanmirod/generadores-en-javascript-47c4</link>
      <guid>https://dev.to/juanmirod/generadores-en-javascript-47c4</guid>
      <description>&lt;p&gt;Los generadores son una herramienta de programación muy poderosa, pero difícil de entender cuando la vemos por primera vez. En este artículo trataré de definir de forma lo más sencilla posible qué son y como se usan los generadores y pasar a varios ejemplos prácticos en los que los generadores nos permiten simplificar código o directamente hacer cosas que no pensábamos que se pudieran hacer en JavaScript como funciones de evaluación perezosa y corutinas.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué es un generador?
&lt;/h3&gt;

&lt;p&gt;Un generador es una función especial en JavaScript que puede pausar su ejecución y retomarla en un punto arbitrario. Para definirlos utilizamos dos nuevas palabras reservadas del lenguaje: &lt;code&gt;function*&lt;/code&gt; y &lt;code&gt;yield&lt;/code&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Este es uno de los casos más claros en los que he encontrado que la barrera del idioma a veces dificulta la comprensión de ciertos conceptos. &lt;code&gt;yield&lt;/code&gt; es una palabra poco habitual en inglés, y para un no-nativo como yo, me suena totalmente fuera de contexto. Se traduce como &lt;em&gt;producir&lt;/em&gt; o &lt;em&gt;ceder&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Trataré de explicar su funcionamiento con un ejemplo de código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;counterGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;
    &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counterGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// { value: 0, done: false }&lt;/span&gt;
&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// { value: 1, done: false }&lt;/span&gt;
&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// { value: 2, done: false }&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// hasta el infinito y más allá!&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Este sencillo ejemplo muestra el funcionamiento de un generador. El uso más habitual de los generadores es &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators"&gt;crear &lt;em&gt;Iteradores&lt;/em&gt;&lt;/a&gt;. Un &lt;em&gt;Iterador&lt;/em&gt; es un objeto que devuelve un elemento de una colección cada vez que llamamos a su método &lt;code&gt;.next&lt;/code&gt;. &lt;code&gt;counterGenerator&lt;/code&gt; devuelve un iterador que asignamos a la variable counter.&lt;/p&gt;

&lt;p&gt;Los generadores siempre devuelven un iterador y en el momento en el que llamamos al método &lt;code&gt;.next&lt;/code&gt; del iterador, éste ejecuta la función del generador hasta llegar al primer &lt;code&gt;yield&lt;/code&gt; que encuentra, que detiene la ejecución de la función y &lt;em&gt;produce&lt;/em&gt; un resultado, o dicho de otra forma, produce un elemento de la colección. &lt;/p&gt;

&lt;p&gt;El resultado es siempre un objeto con dos propiedades, &lt;code&gt;value&lt;/code&gt; y &lt;code&gt;done&lt;/code&gt;, en la primera está el valor producido por &lt;code&gt;yield&lt;/code&gt; y la segunda es para indicar si el iterador ha terminado, es decir, si ese era el último elemento de la colección. &lt;/p&gt;

&lt;p&gt;En la siguiente llamada a &lt;code&gt;.next&lt;/code&gt; la función continúa desde el &lt;code&gt;yield&lt;/code&gt; y hasta el siguiente &lt;code&gt;yield&lt;/code&gt;, y así hasta encontrar un &lt;code&gt;return&lt;/code&gt; que devolverá &lt;code&gt;true&lt;/code&gt; como valor de &lt;code&gt;done&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El iterador devuelto por &lt;code&gt;counterGenerator&lt;/code&gt; Puede usarse a su vez dentro de un bucle &lt;code&gt;for of&lt;/code&gt;, ya que estos bucles utilizan el interface del iterador para obtener el valor de cada iteración:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="c1"&gt;// break detiene el bucle for como si hubiera encontrado done === true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="c1"&gt;// 10&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bucles infinitos y evaluación perezosa
&lt;/h3&gt;

&lt;p&gt;En el ejemplo anterior hemos usado todo el tiempo un bucle &lt;code&gt;while (true)&lt;/code&gt; sin bloquear o saturar la cpu y sin ninguna alerta por parte de node. Esto es así porque &lt;code&gt;yield&lt;/code&gt; pausa la &lt;br&gt;
ejecución de la función, y por lo tanto, pausa el bucle infinito, cada vez que produce un valor.&lt;/p&gt;

&lt;p&gt;Esto es lo que se llama &lt;em&gt;evaluación perezosa&lt;/em&gt; y es un concepto importante en lenguajes funcionales como Haskell. Básicamente nos permite tener listas o estructuras de datos &lt;em&gt;"infinitas"&lt;/em&gt; y operar sobre ellas, por ejemplo podemos tener un operador &lt;code&gt;take(n)&lt;/code&gt; que toma los N primeros elementos de una lista infinita:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;oddsGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;oddNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oddsGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// TODOS los números impares &lt;/span&gt;

&lt;span class="nx"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oddNumbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// toma 5 números impares&lt;/span&gt;
&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="c1"&gt;// 5&lt;/span&gt;
&lt;span class="c1"&gt;// 7&lt;/span&gt;
&lt;span class="c1"&gt;// 9&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;La evaluación perezosa permite construir este tipo de estructuras &lt;em&gt;"infinitas"&lt;/em&gt; o completas sin producir errores de ejecución y también son más eficientes en algoritmos de búsqueda, recorrido de árboles y cosas así, al evaluar el mínimo número de nodos necesarios para encontrar la solución. Para ver más usos y ventajas de la evaluación perezosa puedes ver &lt;a href="https://stackoverflow.com/questions/265392/why-is-lazy-evaluation-useful"&gt;este hilo de stackoverflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como añadido en JavaScript, los generadores nos permiten crear una sintaxis más legible en el uso de arrays. Podemos obtener los valores producidos por el generador en ES6 mediante el &lt;em&gt;spread operator&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;
    &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="c1"&gt;// [ 0, 1, 2, 3, 4 ] &lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Pero cuidado con utilizar el &lt;em&gt;spread operator&lt;/em&gt; o los bucles for con listas infinitas como la de arriba:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;oddNumbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// bucle infinito!!&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;oddNumbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// bucle infinito y 'out of memory', no podemos crear un array infinito en la memoria!!&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Async/await y corutinas
&lt;/h3&gt;

&lt;p&gt;Además de la generación de iteradores, los generadores nos permiten controlar la ejecución de funciones asíncronas gracias al mecanismo de pausa de la función de &lt;code&gt;yield&lt;/code&gt;. Para explicar por qué esto es importante, vamos a desviarnos un momento y hablar de &lt;code&gt;async/await&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Una de las funcionalidades más coreadas de ES7 son las nuevas construcciones &lt;code&gt;async&lt;/code&gt; y &lt;code&gt;await&lt;/code&gt;, que nos permiten ejecutar código asíncrono pero escribiéndolo de forma lineal, sin necesidad de pensar en callbacks o promesas. Veamos cómo funciona:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;helloDelayed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;helloDelayed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// a los 5 segundos aparece 'Hello'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Lo genial de &lt;code&gt;async/await&lt;/code&gt; es que el código de la función async es lineal, le hemos pasado una promesa a await y nos devuelde directamente el valor con el que se ha resuelto, esperando y deteniendo la ejecución de la función.&lt;/p&gt;

&lt;p&gt;No me voy a detener más en explicar cómo funciona, eso lo dejo para otro post, pero &lt;code&gt;async/await&lt;/code&gt; en realidad no es más que un uso concreto de los generadores, &lt;em&gt;azúcar sintáctico&lt;/em&gt; para usar un generador y evaluar una promesa, podríamos replicar esta funcionalidad, para una sola llamada (más adelante veremos la generalización) así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;helloDelayed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nx"&gt;helloDelayed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;hi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Esta solución es más difícil de leer y de escribir, sobre todo por el doble &lt;code&gt;.next&lt;/code&gt; necesario para que funcione, y por la poca legibilidad del comando &lt;code&gt;yield&lt;/code&gt; en si mismo. Pero muestra una parte importante del funcionamiento de los generadores. &lt;/p&gt;

&lt;p&gt;Lo que está pasando aquí es que &lt;code&gt;hi&lt;/code&gt; recibe un generador como parámetro, lo ejecuta y llama una vez a &lt;code&gt;.next&lt;/code&gt; para ejecutar el generador hasta el yield y luego lo vuelve a llamar cuando tiene el resultado de la promesa para revolver el resultado al yield. &lt;/p&gt;

&lt;p&gt;Hasta ahora no habíamos hablado de esto para no complicar más, pero podemos añadir a la llamada a &lt;code&gt;.next&lt;/code&gt; un parámetro, que a su vez podemos capturar en una variable asignándola a &lt;code&gt;yield&lt;/code&gt;. Esta, para mi, es la funcionalidad más confusa de los generadores, pero es la clave para usarlos para ejecutar llamadas asíncronas o corutinas como veremos en los siguientes ejemplos. Veamos un pequeño ejemplo de como funciona:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;counterGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counterGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// { value: 0, done: false }&lt;/span&gt;
&lt;span class="c1"&gt;// el primer 'next' no imprime nada porque el generador se ejecuta solo hasta el yield&lt;/span&gt;
&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ho&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// ho&lt;/span&gt;
&lt;span class="c1"&gt;// { value: 1, done: false }&lt;/span&gt;
&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// hu&lt;/span&gt;
&lt;span class="c1"&gt;// { value: 2, done: false }&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Este mecanismo nos da una forma de comunicarnos con el generador, algo muy potente, aunque en mi opinión con una sintaxis difícil de leer y nada clara. Los generadores no son una herramienta que hay que usar con moderación, pero nos permiten hacer cosas que estarían fuera del alzance de JavaScript si no fuera con ellos, como el ejemplo que veremos a continuación.&lt;/p&gt;

&lt;p&gt;Generalizando el código de helloDelayed, se puede construir una función que controle la ejecución de funciones asíncronas prácticamente igual a como hace &lt;code&gt;async/await&lt;/code&gt;, veamos un ejemplo que lee dos ficheros (ejemplo tomado de &lt;a href="https://medium.com/@tjholowaychuk/callbacks-vs-coroutines-174f1fe66127"&gt;este post de TJ HoloWaychuck&lt;/a&gt;, que recomiendo leer, el código original usa callbacks, pero lo he modificado para usar promesas, dos ejemplos por el precio de uno &lt;em&gt;;)&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="nx"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;README.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Este código, sí se parece mucho más al de &lt;code&gt;async/await&lt;/code&gt;, es más, si cambiamos &lt;code&gt;thread&lt;/code&gt; por &lt;code&gt;async&lt;/code&gt; y imaginamos que &lt;code&gt;yield&lt;/code&gt; es &lt;code&gt;await&lt;/code&gt; es prácticamente igual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;README.md&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Este ejemplo básico es una simplificación de la librería &lt;a href="https://github.com/tj/co"&gt;Co&lt;/a&gt;, que nos permite escribir este tipo de código asíncrono de forma lineal y con la seguridad de que captura todas las excepciones de forma parecida a como hacen las Promesas.&lt;/p&gt;

&lt;p&gt;Técnicamente esto no son corutinas. En realidad, cuando hablamos de generadores, hablamos de &lt;a href="https://en.wikipedia.org/wiki/Coroutine#Comparison_with_generators"&gt;&lt;em&gt;'semicorutinas'&lt;/em&gt;&lt;/a&gt; porque los generadores no son tan flexibles como las corutinas de lenguajes como Go, pero diremos que son equivalentes a corutinas, aún sabiendo que estamos simplificando, porque es la herramienta que tenemos para esta función en JavaScript a nivel nativo. &lt;/p&gt;

&lt;p&gt;En cuando a otras librerías para corutinas, &lt;a href="https://github.com/fibjs/fibjs"&gt;fibjs&lt;/a&gt; y &lt;a href="https://github.com/laverdet/node-fibers"&gt;node-fibers&lt;/a&gt; son implementaciones de &lt;em&gt;'fibers'&lt;/em&gt; que podríamos traducir como &lt;em&gt;"fibras"&lt;/em&gt; o &lt;em&gt;"hilos ligeros"&lt;/em&gt; que es más flexible que los generadores y que algunos desarrolladores &lt;a href="https://github.com/nodejs/node/issues/9131"&gt;quieren incluir en el núcleo de Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Los generadores y las corutinas son herramientas avanzadas del lenguaje que seguramente no tengas que utilizar directamente a no ser que hagas desarrollo de sistemas o librerías, pero de las que podemos sacar provecho en nuestro código con librerías como &lt;code&gt;Co&lt;/code&gt;, &lt;code&gt;node-fibers&lt;/code&gt; o el nuevo &lt;code&gt;async/await&lt;/code&gt; nativo. Espero que estos ejemplos hayan resuelto algunas dudas y generado aun más dudas e interés por el lenguaje y sirva como introducción a todo este tema.&lt;/p&gt;

&lt;p&gt;Otra lectura recomendada para profundizar en los Generadores es el libro de Kyle Simpson ES6 and Beyond, y en concreto &lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch3.md#generators"&gt;el capítulo sobre Iteradores y Generadores&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Tests unitarios en JavaScript con Jasmine</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Thu, 07 Jun 2018 21:54:12 +0000</pubDate>
      <link>https://dev.to/juanmirod/tests-unitarios-en-javascript-con-jasmine-118e</link>
      <guid>https://dev.to/juanmirod/tests-unitarios-en-javascript-con-jasmine-118e</guid>
      <description>&lt;p&gt;Los tests unitarios son una herramienta excelente para prevenir bugs en ejecución y para describir el comportamiento que debe tener el código. Además, y &lt;a href="http://research.microsoft.com/en-us/groups/ese/nagappan_tdd.pdf"&gt;sobre todo si se realizan antes que el código&lt;/a&gt; de la aplicación (lo que se conoce como &lt;strong&gt;TDD&lt;/strong&gt;), los test unitarios ayudan a estructurar mejor el código, hacerlo más modular e independiente y además ayudan a dividir los problemas y hacerlos más sencillos de programar.&lt;/p&gt;

&lt;p&gt;En JavaScript, &lt;a href="https://jasmine.github.io/2.4/introduction.html"&gt;Jasmine&lt;/a&gt; es un framework de test que permite crear tests fáciles de leer de forma que sirven también de documentación para el código. Así, usando Jasmine, si queremos escribir una suit de tests para una función que suma dos números llamada 'add' la escribiríamos así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should add two numbers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
      &lt;span class="c1"&gt;// código del test&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should throw an error if you try to add strings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
      &lt;span class="c1"&gt;// código del test&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="p"&gt;})&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Vamos a ver algunos ejemplos de código y sus correspondientes tests. El proyecto es una sencilla calculadora en JavaScript, pero es diferente a los típicos ejemplos de calculadoras en javascript, ya que en esta no se utiliza eval para calcular los resultados, sino que el input se valida y las operaciones están limitadas a las que están definidas. Para ello he creado dos pequeños módulos, uno para la lógica y otro para el interface. &lt;/p&gt;

&lt;p&gt;El proyecto es un ejemplo sencillo, según las especificaciones de cada proyecto serán pertinentes más o menos tests y habrá que controlar casos más concretos, espero que este proyecto sirva de ejemplo aunque no sea muy exhaustivo ni tenga muchos requisitos.&lt;/p&gt;

&lt;p&gt;Empezaremos con los test de la clase que controla el funcionamiento de la calculadora por ser más sencillo. Cuando tienes una clase que no realiza operaciones de entrada salida, ni modifica el DOM o interacciones del usuario es mucho más sencillo escribir los tests. A eso me refería antes con que escribir los tests primero te ayuda a separar el código y a promueve mucho el principio de que cada función se encargue sólo de una cosa. En problemas fáciles como este de la calculadora, es fácil verse tentado a poner todo el código junto, meter un par de funciones en el código que maneja el interface y listo. &lt;/p&gt;

&lt;p&gt;El problema viene a largo plazo, cuando el cliente dice que además de calcular tiene que mostrar el resultado intermedio y luego te dicen que al meter un símbolo que no debería hacer nada la calculadora da un error muy feo, o que debería poder guardar en memoria un resultado... Y empezamos a poner más código en esas funcioncitas en medio del interface y esas funcioncitas van creciendo hasta tener cientos de líneas de código y... seguro que ya sabes por donde voy. Nuestra sencilla calculadora, que habíamos programado en un par de horas, crece hasta convertirse en una pesadilla de mantener y de modificar. Y además nuestro jefe no entiende cómo puede ser que hicieramos la calculadora en un día pero ahora para añadir una funcionalidad &lt;em&gt;obvia&lt;/em&gt; tardemos una semana.&lt;/p&gt;

&lt;p&gt;Por eso es por lo que en esta ocasión vamos a usar TDD y vamos a escribir primero unos tests de lo que queremos que nuestra calculadora haga:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Calculator.spec.js&lt;/span&gt;
&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Calculator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should have a storeAction function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBeDefined&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storeAction&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RESET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return the last result for unkown actions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HI&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should add numbers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ADD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RESULT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should multiply numbers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MULTIPLY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RESULT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="p"&gt;});&lt;/span&gt; 

&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Bien, ya sabemos lo que queremos, una calculadora que sume y multiplique, y que no admita cualquier cosa por la entrada. Para implementar esto nuestro Módulo calculadora debe tener una función &lt;code&gt;storeAction&lt;/code&gt; que será la que utilizaremos para introducir la siguiente operación o número sobre el que la calculadora debe operar, imitando el funcionamiento normal de una calculadora clásica. La functión &lt;strong&gt;beforeEach&lt;/strong&gt; es una función de &lt;em&gt;Jasmine&lt;/em&gt; que se ejecutará antes de cada función &lt;strong&gt;it&lt;/strong&gt; y que nos sirve para asegurarnos de que antes de cada test partimos del mismo estado inicial.&lt;/p&gt;

&lt;p&gt;Estos tests están bien para comenzar, pero si nos fijamos veremos que hay muchos más casos que controlar, como ¿qué pasa si añado dos números seguidos? ¿y si añado dos operaciones? ¿Donde está el test para la función de &lt;em&gt;RESET&lt;/em&gt;? Todos estos test deberán ir añadiendose y satisfaciéndose en el código.&lt;/p&gt;

&lt;p&gt;Si solo tenemos los tests y los ejecutamos en la línea de comandos o en el navegador, veremos que fallan. Para ejecutarlos lo más sencillo es crear un fichero &lt;em&gt;html&lt;/em&gt; en el que añadiremos los scripts de jasmine que están alojados en el CDN de jsdeliver. A continuación añadimos los ficheros js de nuestra aplicación y los ficheros que contienen los tests para los diferentes módulos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sample Unit tests runner&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/jasmine/2.4.1/jasmine.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/jasmine/2.4.1/jasmine.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/jasmine/2.4.1/jasmine-html.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/jasmine/2.4.1/boot.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"calculator.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"calculator.spec.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;


&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al abrir este fichero en el navegador, Jasmine creará un pequeño interface y listará los tests junto con los resultados y los errores que hayan ocurrido. En este caso, si sólo tenemos el fichero de especificaciones, todos los tests fallarán.&lt;/p&gt;

&lt;p&gt;Para satisfacerlos, deberemos crear el módulo &lt;strong&gt;Calculator&lt;/strong&gt; y añadir la función &lt;strong&gt;storeAction&lt;/strong&gt; con la funcionalidad suficiente para que satisfaga los tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Calculator.js&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;Calculator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strict mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nx"&gt;lastResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nx"&gt;setLastResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;lastResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

    &lt;span class="na"&gt;isNumeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;storeAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isNumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isNumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ADD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;setLastResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastResult&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MULTIPLY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;setLastResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastResult&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;setLastResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// new operation&lt;/span&gt;

        &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isNumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

          &lt;span class="nx"&gt;setLastResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RESET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

          &lt;span class="nx"&gt;setLastResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;}&lt;/span&gt; 

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;lastResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;})();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Este código satisface los tests de arriba y algunos más. Aún nos quedaría añadir la funcionalidad para restar, dividir, limpiar el input, etc. Puedes ver el ejemplo algo más completo en &lt;a href="https://thimbleprojects.org/juanmirod/56250/"&gt;este thimble&lt;/a&gt;. Para ver el resultado de los tests haz click en el fichero 'test.html'.&lt;/p&gt;

&lt;p&gt;Si te fijas, en ese projecto no hay tests para la parte del interface de la calculadora. Hay funciones del interface que no tiene mucho sentido testar, el markup puede cambiar sin alterar la funcionalidad y no tiene mucho sentido escribir tests para algo así. Pero sí que podemos escribir tests que verifiquen que, cuando hago click en un botón o pulso una tecla, se llama a la función adecuada. Estos tests son algo más complicados  ya que tenemos que capturar los eventos y espiar las funciones que estos deben llamar. &lt;/p&gt;

&lt;p&gt;Thimble es una buena herramienta para practicar TDD ya que el proyecto se va guardando y la vista se actualiza de forma automática. Pero necesitamos de conexión a internet y no tiene la velocidad y las ayudas de editores como Sublime o VSCode. Para conseguir que la vista se actualice automáticamente como en Thimble en nuestro proyecto en local podemos utilizar varias herramientas diferentes. En el siguiente artículo me centraré en cómo añadir &lt;a href="https://karma-runner.github.io/0.13/index.html"&gt;Karma&lt;/a&gt; a nuestro proyecto y utilizarlo para trabajar con TDD. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>spanish</category>
      <category>testing</category>
    </item>
    <item>
      <title>Ámbito léxico y de bloque en JavaScript</title>
      <dc:creator>Juan Miguel Rodriguez Ceron</dc:creator>
      <pubDate>Thu, 07 Jun 2018 21:45:27 +0000</pubDate>
      <link>https://dev.to/juanmirod/mbito-lxico-y-de-bloque-en-javascript-868</link>
      <guid>https://dev.to/juanmirod/mbito-lxico-y-de-bloque-en-javascript-868</guid>
      <description>&lt;p&gt;El ámbito de las variables en JavaScript puede ser un poco confuso a veces, pero en realidad sólo hay que seguir un par de reglas para saber a qué ámbito pertenece una variable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;En JavaScript &lt;strong&gt;las funciones tienen su propio ámbito léxico&lt;/strong&gt;, lo que quiere decir que depende de cómo son declaradas en el código y no de cuando se ejecutan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sólo las funciones&lt;/strong&gt; pueden crear un nuevo ámbito y como excepción, los bloques &lt;strong&gt;catch&lt;/strong&gt; también crean su propio ámbito. Con la introducción de las variables &lt;code&gt;let&lt;/code&gt; y &lt;code&gt;const&lt;/code&gt; en ES6, también tenemos a nuestra disposición ámbito de bloque, ver más abajo para ver qué significa esto.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;¿Cómo funciona este ámbito léxico de las funciones? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A la hora de decidir a qué ámbito pertenece una variable, el compilador de JavaScript comprueba si la variable está declarada dentro de la función donde se invoca (ámbito local de la función) si no es así, busca en el ámbito de la función que la contenga y así hasta llegar al ámbito global. &lt;strong&gt;Si la variable no fue declarada en ningún momento, el compilador la declara como variable global&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;En 'Strict mode' el compilador no creará la nueva variable en ámbito global sino que devolverá un error por variable no declarada.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La mejor forma de ver cómo funcionan estas reglas es probándolas en directo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//'use strict'; // descomentar para ver el error al usar la variable bye&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Global: I am global. &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ObjectWithPrivateVariables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ObjectDefinition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Esta variable está definida dentro del ámbito de la functión ObjectDefinition&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Object: Hello. &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="c1"&gt;//var bye; // descomentar para arreglar la fuga de la variable bye al ámbito global&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;returnsAGreeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// El ámbito de esta función está dentro del ámbito de OnjectDefinition&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;sayBye&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;byes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;bye&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Good bye!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bye&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;newObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ObjectWithPrivateVariables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;newObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt; &lt;span class="c1"&gt;// Accede a la variable Global&lt;/span&gt;
&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;newObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sayBye&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;bye&lt;/span&gt; &lt;span class="c1"&gt;// Esta variable se ha declarado como global y podemos acceder a ella, cuidado!!&lt;/span&gt;
&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;sayHi&lt;/span&gt; &lt;span class="c1"&gt;// sayHi es undefined&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://jsfiddle.net/juanmirod/zgsgqz2j/"&gt;Editar en jsfiddle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es interesante jugar un poco con el script, mover las declaraciones de sitio y ver que pasa. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ok, lo he pillado y ahora ¿Qué es eso del ámbito de bloque?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En ES6 se introdujeron los tipos de variable &lt;code&gt;let&lt;/code&gt; y &lt;code&gt;const&lt;/code&gt; que no funcionan como las variables &lt;code&gt;var&lt;/code&gt; sino que tienen ámbito de bloque (block scope). Esto significa que estas variables existen dentro del bloque donde son declaradas, independientemente de si ese bloque es una función, una condición o un bucle. Además, las variables declaradas con let y const no se pueden utilizar antes de ser declaradas. &lt;/p&gt;

&lt;p&gt;Esto es muy útil para declarar variables dentro de bucles o condiciones y que estas variables no se &lt;em&gt;"filtren"&lt;/em&gt; al ámbito de la función. Siempre es más fácil explicarlo con un poco de código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;countTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// console.log(i) // descomentar dará un error, i no está definida&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// console.log(i) // descomentar dará un error, i no está definida&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;countTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://jsfiddle.net/juanmirod/r2wLyvg3/"&gt;Editar en jsfiddle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Algo muy curioso de este pequeño código es el diferente resultado de los dos primeros &lt;code&gt;console.log&lt;/code&gt; Las variables &lt;code&gt;let&lt;/code&gt; y &lt;code&gt;const&lt;/code&gt; no permiten ser usadas antes de ser declaradas, pero las variables declaradas con &lt;code&gt;var&lt;/code&gt; sí. Esto es debido a una propiedad que se llama &lt;code&gt;hoisting&lt;/code&gt;, que quiere decir que el compilador de JavaScript hace una primera pasada por todo el código para ver qué variables y funciones hemos definido y asignarles su ámbito. Hasta que la ejecución no llegue al punto de la asignación la variable tendrá el valor &lt;code&gt;undefined&lt;/code&gt;. Esto no ocurre con &lt;code&gt;let&lt;/code&gt; y &lt;code&gt;const&lt;/code&gt;, que no son creadas hasta que la ejecución no llega al punto donde son declaradas. Así, si creamos una variable de bloque dentro de una condición que no se cumple, nunca se creará, y estaremos ahorrando ese tiempo y esa memoria.&lt;/p&gt;

&lt;p&gt;Estas propiedades hacen que las variables &lt;code&gt;let&lt;/code&gt; y &lt;code&gt;const&lt;/code&gt; sean consideradas más fáciles de entender, que es lo importante, y actualmente las guías de estilo de código recomienden su uso sobre var. Si usas un linter, lo más seguro es que, si usas var, te lo marque como un warning o un error.&lt;/p&gt;

&lt;p&gt;La diferencia entre let y const es que las variables &lt;code&gt;const&lt;/code&gt; no se pueden reasignar, con lo que en el caso de valores escalares (cadenas, números y booleanos) son efectivamente constantes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="c1"&gt;// ningún problema&lt;/span&gt;
&lt;span class="c1"&gt;// y = 8 // Error, 'y' no puede volver a asignarse por ser una constante&lt;/span&gt;

&lt;span class="c1"&gt;// pt = 'otracosa' // Error, pt no puede volver a asignarse&lt;/span&gt;

&lt;span class="nx"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="c1"&gt;// sin problema, ahora pt.x vale 15 en lugar de 0&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;En el ejemplo de código puede verse que no ocurre así con los objetos, porque lo que no se puede modificar es la referencia que contiene esa variable, pero sí podremos modificar las propiedades internas del objeto, (a no ser que estén congeladas, pero de eso hablaremos otro día).&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>spanish</category>
      <category>scope</category>
      <category>ámbito</category>
    </item>
  </channel>
</rss>
