<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>With a Twist</title>
  <subtitle>Software Development</subtitle>
  <id>https://withatwist.dev/</id>
  <link href="https://withatwist.dev/"/>
  <link href="https://withatwist.dev/feed.xml" rel="self"/>
  <updated>2026-06-04T00:00:00+00:00</updated>
  <author>
    <name>Mauro Otonelli, Sebastian Armano, Tute Costa</name>
  </author>
  <entry>
    <title>One Telegram contact to rule my team of AI agents</title>
    <link rel="alternate" href="https://withatwist.dev/one-telegram-contact-to-rule-my-team-of-ai-agents.html"/>
    <id>https://withatwist.dev/one-telegram-contact-to-rule-my-team-of-ai-agents.html</id>
    <published>2026-06-04T00:00:00+00:00</published>
    <updated>2026-06-05T15:51:12+00:00</updated>
    <author>
      <name>Tute Costa</name>
    </author>
    <summary type="html">&lt;p&gt;Siri doesn’t understand Argentinian Spanish.
I have to pronounce some words in a neutral accent, which sounds weird here, and my toddlers learn it as local, or write them out, navigating the awkward iOS cursor, or tap each letter and then correct typos.
I use calendar, timers, notes, and reminders as anyone else, and I’ve been a “tech person” since my early years.&lt;/p&gt;

&lt;p&gt;So I was surprised &lt;em&gt;by my own surprise&lt;/em&gt; when Fede, my brother-in-law, &lt;strong&gt;repeated my ask to his Telegram agent&lt;/strong&gt;: “remind me to pick up the kids at 11:30”. Well that was simple, and it wouldn’t rely on our memory. He didn’t write or pronounce how Siri expects, he just said my words to his phone. I’ve long wanted to schedule calendar events via voice while on the go. Siri promised this for long too, but it never quite delivered.&lt;/p&gt;

&lt;p&gt;Three weeks later I had five specialized AI agents running on my iMac under an orchestrator.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Siri doesn’t understand Argentinian Spanish.
I have to pronounce some words in a neutral accent, which sounds weird here, and my toddlers learn it as local, or write them out, navigating the awkward iOS cursor, or tap each letter and then correct typos.
I use calendar, timers, notes, and reminders as anyone else, and I’ve been a “tech person” since my early years.&lt;/p&gt;

&lt;p&gt;So I was surprised &lt;em&gt;by my own surprise&lt;/em&gt; when Fede, my brother-in-law, &lt;strong&gt;repeated my ask to his Telegram agent&lt;/strong&gt;: “remind me to pick up the kids at 11:30”. Well that was simple, and it wouldn’t rely on our memory. He didn’t write or pronounce how Siri expects, he just said my words to his phone. I&amp;rsquo;ve long wanted to schedule calendar events via voice while on the go. Siri promised this for long too, but it never quite delivered.&lt;/p&gt;

&lt;p&gt;Three weeks later I had five specialized AI agents running on my iMac under an orchestrator.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;Need zero, pick an agent architecture&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve been meaning to implement agents but struggled to pick a solution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RubyLLM looked too low-level (last month): I was looking for a simple system but with predefined structure. It&amp;rsquo;s quickly evolving though&lt;/li&gt;
&lt;li&gt;OpenClaw is powerful but ginormous, a big bundle of prompts, and I would never fully control the details of its functioning&lt;/li&gt;
&lt;li&gt;NanoClaw seemed closer to what I’d like, but if it’s so simple, why not roll my own from scratch?&lt;/li&gt;
&lt;li&gt;My own from scratch: where do I even start?&lt;/li&gt;
&lt;li&gt;Mastra, a TypeScript framework for building AI agents, initially felt like much more than I needed. I eagerly watched &lt;a href="https://www.youtube.com/@damian.galarza"&gt;Damian Galarza&amp;rsquo;s videos&lt;/a&gt;, but I couldn&amp;rsquo;t predict what exactly each dashboard item does&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My ex coworker Anthony Costanzo provided an onramp I needed:
he built his &lt;a href="https://acoz.dev/blog/the-batcomputer-alfred/"&gt;Batcomputer from the ground up, and shared his notes&lt;/a&gt;.
He used familiar tools for programmers: a long-running Claude Code session within tmux,
reachable via Telegram with Tailscale, launching on boot using macOS’s LaunchAgents, and a directory of markdown files for memory with auto-commit.
This was right up my alley, it would help me &lt;strong&gt;delineate what “my own agent” even means&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I added voice note transcription via OpenAI’s whisper, registered a Google account for my agent (Dino) with API access, and a new macOS non-admin user on my iMac for isolation.&lt;/p&gt;

&lt;p&gt;Dino also sends me a daily morning brief with my schedule and unread emails. It can also send emails, but with this implementation I worried it may spam people even though its prompt said &amp;ldquo;don&amp;rsquo;t without my consent&amp;rdquo;. &lt;strong&gt;A prompt does not suffice to guarantee such rules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I gave him readonly access to my email and calendar: &lt;strong&gt;I don&amp;rsquo;t want an agent to impersonate me, nor do I want it to exfiltrate or commit mistakes with my data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It worked, but showed rough edges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screen-scraping tmux couldn&amp;rsquo;t distinguish a tool working from a finished response&lt;/li&gt;
&lt;li&gt;Adding a second agent meant a second tmux session, a second polling loop, and hand-rolled connections between them&lt;/li&gt;
&lt;li&gt;Multi-turn context lived only in the pane&amp;rsquo;s scrollback buffer&lt;/li&gt;
&lt;li&gt;Memory wasn&amp;rsquo;t efficient&lt;/li&gt;
&lt;li&gt;Iterating on prompts and testing them with real usage &lt;strong&gt;felt like when I updated PHP websites before learning about automated tests&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It proved the concept: a personal agent I can configure with precision, reachable from my phone, understanding both my English and Argentinian Spanish.
But I wouldn&amp;rsquo;t grow it on that early foundation.&lt;/p&gt;

&lt;p&gt;I took another look at the implementation options. I rewatched Damian&amp;rsquo;s videos on Mastra and now it clicked.
“Framework” means decisions taken for me, in this case proposing a sensible structure.
Mastra has a declarative API that makes for readable code.
&lt;strong&gt;I rewrote Dino in Mastra. And now I could understand its features&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Like, add a &amp;ldquo;Human In The Loop&amp;rdquo; approval requirement before sending emails.
Now I can comfortably ask Dino to try sending an email, inspect what it plans to do, and only then approve the operation or request changes.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;First need: Maybe a second agent&lt;/h2&gt;

&lt;p&gt;As Dino proved its worth, I started asking more of it. It started remembering how I use calendar, email, Telegram, plus the communication styles I prefer. And it began mixing preferences up.&lt;/p&gt;

&lt;p&gt;Another problem: every request was handled by the smart (and expensive) LLM model, but some simpler operations can be done by cheaper models, in turn faster.&lt;/p&gt;

&lt;p&gt;On May 10th &lt;strong&gt;I split an orchestrator and a worker&lt;/strong&gt;.
Manuel became the smart orchestrator handling Telegram conversations, memories, and deciding delegations.
Dino kept its calendar and email fu, becoming a simpler, more focused utility agent who knew one thing well.
Dino doesn’t have much of a personality or agency, but boy does it fill event details and invitees from my natural language instructions properly.
No forms, double verification of whether I’m picking the right week, or timezone musings needed anymore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This pattern unlocked everything that follows.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="wide"&gt;
&lt;img src="/images/2026-06-agents-tree.svg" alt="Tute talks to Manuel, who delegates to Dino, Topo, Tito, Jaime, and Fede"&gt;
&lt;/div&gt;

&lt;p&gt;You may think: how do you keep track of names that don&amp;rsquo;t even have faces?
I don&amp;rsquo;t. I have a single Telegram contact to access everything: Manuel.
I say what I need in either language I&amp;rsquo;m using, and Manuel routes it.
&lt;strong&gt;I couldn&amp;rsquo;t build a simpler UX for this functionality, and that&amp;rsquo;s why it sticks&lt;/strong&gt; unlike other &amp;ldquo;intelligences&amp;rdquo; and apps I&amp;rsquo;ve tried before.&lt;/p&gt;

&lt;h2&gt;Second need: self-improving agents&lt;/h2&gt;

&lt;p&gt;Sometimes I’d ask Manuel to make changes to the project itself:&lt;/p&gt;

&lt;blockquote&gt;
&amp;ldquo;Fix all-day events time boundaries.&amp;rdquo;
&lt;br&gt;
&amp;ldquo;Add support for recurring events&amp;rdquo;
&lt;/blockquote&gt;

&lt;p&gt;Manuel would counter he has no tools to write code.
I&amp;rsquo;d sit on my computer, copy the failed request into Cursor, and redeploy.&lt;/p&gt;

&lt;p&gt;On May 14th I added &lt;strong&gt;Topo&lt;/strong&gt;, a sub-agent with Mastra&amp;rsquo;s Workspace API, allowing
access to the project’s directory
and to relevant shell commands.&lt;/p&gt;

&lt;p&gt;I can now tell Manuel to add a capability to an agent, and it&amp;rsquo;ll delegate to Topo. The sub-agent implements it, and reports back the generated
commit SHA as verifiable evidence of work
(without it, LLMs can and will &lt;strong&gt;report back enthusiastic success with no changes done&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The friction between &amp;ldquo;I want this feature&amp;rdquo; and &amp;ldquo;the feature exists&amp;rdquo; dropped to near zero.&lt;/strong&gt; And in my agents team I optimistically let it deploy its changes: most often it works, and when not it’s easy for me to roll back or fix.
I still review all commits to tweak anything needed and to learn, but not before letting it update itself.&lt;/p&gt;

&lt;h2&gt;Third need: invoicing for my company with Tito agent&lt;/h2&gt;

&lt;p&gt;For my company each month-end I have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Review each client&amp;rsquo;s GitHub repos and task managers to gather links to work done&lt;/li&gt;
&lt;li&gt;Write a monthly report summarizing all&lt;/li&gt;
&lt;li&gt;Generate and email an invoice&lt;/li&gt;
&lt;li&gt;Commit compiled notes to my &lt;code&gt;railspilot-documents&lt;/code&gt; repository&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;rsquo;s not a terribly laborious or time-consuming task, but it did distract me the last days of each month with something that didn’t seem to deserve my time. That feeling again, &lt;strong&gt;this mustn’t be hard to automate well&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On May 29th, via Telegram request to Manuel, I created &lt;strong&gt;Tito&lt;/strong&gt;, a RailsPilot bookkeeper agent with a RailsPilot-documents workspace. Tito reads
&lt;code&gt;clients.yml&lt;/code&gt; to list clients and their relevant URLs, fetches merged PRs via git log and GitHub CLI, tasks to my name from their boards, writes
the report, generates the invoice, and pushes its changes.
I say &amp;ldquo;May reports&amp;rdquo; and &lt;strong&gt;it does the work&lt;/strong&gt;, I review the diff, apply small adjustments, and send.&lt;/p&gt;

&lt;p&gt;Each client also has a status file that both Tito and I keep up to date, so it can tell me what’s next for each client, and any deadline to keep top of mind.&lt;/p&gt;

&lt;p&gt;I speak with clients and interpret their needs, which I try to fulfill as well as I can.
I love that work.
&lt;strong&gt;Tedious tasks that are easy to delegate shouldn&amp;rsquo;t eat into it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Fourth need: lights on when I pull into the driveway&lt;/h2&gt;

&lt;p&gt;The underlying need was implementing yet another agent.
Now I got greedy.
Lower value than the previous one, yet still satisfying.&lt;/p&gt;

&lt;p&gt;I have SmartLife (Tuya) smart switches for some lights.
Some evenings I arrive home and enter through the back door, and it&amp;rsquo;s too dark to find the right key.
I would pull my phone&amp;rsquo;s SmartLife app, tap the very small button next to &amp;ldquo;Kitchen Lights&amp;rdquo;, and enter.&lt;/p&gt;

&lt;p&gt;On June 3rd I added Jaime, an agent who talks to
the Tuya Cloud API to control light switches.
Now I tell Siri via my car &amp;ldquo;phone&amp;rdquo; button to Telegram Manuel:&lt;/p&gt;

&lt;blockquote&gt;&amp;ldquo;Encender las luces de la cocina&amp;rdquo;&lt;/blockquote&gt;

&lt;p&gt;And it does, while I park. It&amp;rsquo;s fun, simple, helpful, and has that &amp;ldquo;wow factor&amp;rdquo; that lets people who never thought of agents (and who will never read this blog post) see what they can do.
Like my brother-in-law when he offloaded a reminder to his agent while waiting for a traffic light.&lt;/p&gt;

&lt;p&gt;Jaime may be a shallow and simple agent. He’s still as smart as his Haiku model:
he interprets &amp;ldquo;kitchen&amp;rdquo;, &amp;ldquo;all&amp;rdquo;, &amp;ldquo;back&amp;rdquo; or &amp;ldquo;exterior lights&amp;rdquo; without me having to predefine groups in an app.
People could have done this with Siri, Alexa, and others for years, but while I know many who own them, I know that one weird person who actually uses them in daily life.
She also sells them.
But &lt;strong&gt;almost everyone I know uses a chat app like Telegram every waking hour&lt;/strong&gt;. The user experience is &lt;em&gt;so much&lt;/em&gt; better.&lt;/p&gt;

&lt;h2&gt;Fifth need: writing this article (Fede)&lt;/h2&gt;

&lt;p&gt;I called this one Fede, &lt;a href="https://fedesapuppo.com/blog/"&gt;honoring my brother-in-law’s blog&lt;/a&gt;. I&amp;rsquo;m glad he started it, I&amp;rsquo;m quite enjoying it and you may too.&lt;/p&gt;

&lt;p&gt;When I thought of writing this piece, I first built a subagent to draft it in my voice. It has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read-only access to this Mastra code so he could inspect and describe it&lt;/li&gt;
&lt;li&gt;Email tool via Dino to email drafts when done (Manuel&amp;rsquo;s approval button goes through Fede to Dino. After &lt;a href="https://github.com/mastra-ai/mastra/issues/16861"&gt;a bug fixed in Mastra&lt;/a&gt;, it works surprisingly well)&lt;/li&gt;
&lt;li&gt;Instructions about my voice, audience, and topics I cover&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I told Manuel (typo included):&lt;/p&gt;

&lt;blockquote&gt;&amp;ldquo;Plese write a blog post describing this project&amp;rdquo;&lt;/blockquote&gt;

&lt;p&gt;He delegated to Fede, who read the git history and agent definitions,
and wrote two drafts of this post.&lt;/p&gt;

&lt;h2&gt;Lessons I took, and next steps&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Specialized agents beat one general agent.&lt;/strong&gt; When Manuel started delegating, every interaction got more fruitful. Each agent has a focused set of tools, specific instructions, and a model tuned to its task&amp;rsquo;s cost and complexity. Focused agents are easier to debug and simpler to extend, like classes in Ruby.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evidence over claims.&lt;/strong&gt; Dino has to pass a proof of work before reporting an event created. If it says &amp;ldquo;done, I scheduled X&amp;rdquo; but the response doesn&amp;rsquo;t include the event ID, &lt;strong&gt;execution fails&lt;/strong&gt; and the task is retried. Same principle for Tito and git commit SHAs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory is a sharp tool.&lt;/strong&gt; Subagents have memory disabled except for the current thread. Memories add to their context, and when not relevant it can lead them astray. &lt;strong&gt;The relevant context is in the tools, not in past conversations.&lt;/strong&gt; Manuel does have memory, because he orchestrates: he may need to edit an event just created, or retry a task that didn&amp;rsquo;t properly finish.&lt;/p&gt;

&lt;p&gt;A friend asked me: who should use agents like these?
Pretty much everyone I know. Anyone with a job that has routines will benefit.
&lt;strong&gt;&amp;ldquo;This is tedious, could an agent help me do it?&amp;rdquo;&lt;/strong&gt;
The answer is most often, yes.&lt;/p&gt;

&lt;p&gt;The pattern works: &lt;strong&gt;identify a repetitive task, design and implement an agent and its tools, and assign it tasks.&lt;/strong&gt;
If you want to build something similar, &lt;strong&gt;start with one agent and one real problem.&lt;/strong&gt;
Try Mastra.
Tell me how it goes!&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;Some technical notes if you care for more detail&lt;/h2&gt;

&lt;p&gt;Summary of my AI team so far, their tools and models:&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Key tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Manuel&lt;/td&gt;
&lt;td&gt;Orchestrator&lt;/td&gt;
&lt;td&gt;Opus&lt;/td&gt;
&lt;td&gt;Telegram, memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dino&lt;/td&gt;
&lt;td&gt;Assistant&lt;/td&gt;
&lt;td&gt;Haiku&lt;/td&gt;
&lt;td&gt;Calendar and email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Topo&lt;/td&gt;
&lt;td&gt;Self-improvement&lt;/td&gt;
&lt;td&gt;Opus&lt;/td&gt;
&lt;td&gt;Workspace, shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tito&lt;/td&gt;
&lt;td&gt;Invoicing, progress&lt;/td&gt;
&lt;td&gt;Haiku&lt;/td&gt;
&lt;td&gt;GitHub, file system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jaime&lt;/td&gt;
&lt;td&gt;Smart lights&lt;/td&gt;
&lt;td&gt;Haiku&lt;/td&gt;
&lt;td&gt;Tuya Cloud API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fede&lt;/td&gt;
&lt;td&gt;Writing drafts&lt;/td&gt;
&lt;td&gt;Sonnet&lt;/td&gt;
&lt;td&gt;Email via Dino&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The system runs on my iMac as a macOS LaunchAgent under a dedicated user account.
Secrets live in 1Password, loaded as ENV variables at runtime.
Telegram webhooks reach Manuel via a Tailscale Funnel.
I&amp;rsquo;m using about $60 a month in API usage with it, it feels very high value for low cost to me.
I expect to grow this system with more responsibilities, and learn about evolution, and maintainability.
I&amp;rsquo;m particularly curious about evals: how do I know an agent is doing its job well beyond &amp;ldquo;it seems to work&amp;rdquo;? That&amp;rsquo;s my next path.
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An agent chat turned into a skill, and then it QA'd itself</title>
    <link rel="alternate" href="https://withatwist.dev/an-agent-chat-that-turned-into-skill-that-tests-itself.html"/>
    <id>https://withatwist.dev/an-agent-chat-that-turned-into-skill-that-tests-itself.html</id>
    <published>2026-03-19T00:00:00+00:00</published>
    <updated>2026-06-05T15:51:12+00:00</updated>
    <author>
      <name>Tute Costa</name>
    </author>
    <summary type="html">&lt;p&gt;I had a simple &lt;code&gt;index.html&lt;/code&gt; page, a marketing site for a client in Spanish.
They asked an English version too, so I opened the chat to Claude’s Opus 4.5 model and asked it to create a near-identical &lt;code&gt;en/index.html&lt;/code&gt; with content translated.
Easy peasy.&lt;/p&gt;

&lt;p&gt;I opened both files side by side and skimmed, they looked the same with lines in different languages.
But I’m used to testing changes, and agents find things to fix before I start more careful checking.
While I had this thought, the client recalled they’d need a version in Portuguese as well.
“Sure”.&lt;/p&gt;

&lt;p&gt;Now, would they synchronize updates in Spanish to the other two languages?
Content and design will surely drift.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;I had a simple &lt;code&gt;index.html&lt;/code&gt; page, a marketing site for a client in Spanish.
They asked an English version too, so I opened the chat to Claude&amp;rsquo;s Opus 4.5 model and asked it to create a near-identical &lt;code&gt;en/index.html&lt;/code&gt; with content translated.
Easy peasy.&lt;/p&gt;

&lt;p&gt;I opened both files side by side and skimmed, they looked the same with lines in different languages.
But I&amp;rsquo;m used to testing changes, and agents find things to fix before I start more careful checking.
While I had this thought, the client recalled they&amp;rsquo;d need a version in Portuguese as well.
&amp;ldquo;Sure&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Now, would they synchronize updates in Spanish to the other two languages?
Content and design will surely drift.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;The solution&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://github.com/anthropics/skills/tree/main/skills/skill-creator"&gt;Claude&amp;rsquo;s &lt;code&gt;/skill-creator&lt;/code&gt;&lt;/a&gt;
to &lt;strong&gt;build reusable instructions to check parity across all languages&lt;/strong&gt;. My simple prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a skill to check that the index files read well in all languages (Spanish and English, Portuguese upcoming).
Check translations match, no page has content that the other does not, and that markup and UI looks and behaves the same.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent started writing a Python script to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM structure is identical after normalizing expected differences (like the language switcher)&lt;/li&gt;
&lt;li&gt;Texts that should be translated aren&amp;rsquo;t identical across files&lt;/li&gt;
&lt;li&gt;Same images, same order&lt;/li&gt;
&lt;li&gt;Same stylesheets&lt;/li&gt;
&lt;li&gt;Internal consistency (nav anchors to section IDs, &lt;code&gt;&amp;lt;html lang&amp;gt;&lt;/code&gt; attribute)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I expected hand-wavy, maybe helpful browser-based checks. It wrote a deterministic Python script.&lt;/p&gt;

&lt;h3&gt;A noisy first run&lt;/h3&gt;

&lt;p&gt;I observed its thought process; it started flagging dozens of mismatches.
&lt;strong&gt;Most of them cascaded from a single root cause&lt;/strong&gt;: an extra closing &lt;code&gt;&amp;lt;/div&amp;gt;&lt;/code&gt; in the English file
threw off every structural comparison after it. The output was technically correct, but not helpful as a checklist.&lt;/p&gt;

&lt;p&gt;It iterated: it identified the root divergence pattern, filtered expected differences
(the language switcher, text that&amp;rsquo;s legitimately identical across languages like proper nouns or acronyms),
and re-ran until the output was clean.
It also flagged actual issues it had found while building its skill:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The false positives disappeared. Now only the 2 real problems remain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Two real bugs I&amp;rsquo;d missed&lt;/h3&gt;

&lt;p&gt;The extra &lt;code&gt;&amp;lt;/div&amp;gt;&lt;/code&gt; was a copy-paste error (that didn&amp;rsquo;t break the UI and I hadn&amp;rsquo;t noticed).
And an image at the footer had an old path I hadn&amp;rsquo;t finished migrating.
&lt;strong&gt;The skill caught them while testing itself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/2026-03-19.png" alt="Claude Opus 4.5 finds two bugs while creating the new skill" /&gt;&lt;/p&gt;

&lt;h2&gt;Let&amp;rsquo;s add Portuguese now&lt;/h2&gt;

&lt;p&gt;When I added &lt;code&gt;pt/index.html&lt;/code&gt;, the parity script immediately had a new problem: Spanish and Portuguese share too much vocabulary.
&amp;ldquo;Engenharia&amp;rdquo; and &amp;ldquo;Ingeniería&amp;rdquo; are different enough, but dozens of short terms like proper nouns or abbreviations are identical.
The script was flagging legitimate cognates as missing translations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opus taught the script about language proximity:&lt;/strong&gt; it introduced a &lt;code&gt;CLOSE_LANG_PAIRS&lt;/code&gt; to relate Spanish and Portuguese,
identical text under 30 characters is assumed to be a legitimate cognate and skipped.
For distant pairs (like Spanish and English), any identical text is still suspicious.&lt;/p&gt;

&lt;p&gt;That was creative. A human may get there after a while.
The agent got there in a chat that turned into an effective, reusable skill.&lt;/p&gt;

&lt;h2&gt;Closing thoughts&lt;/h2&gt;

&lt;p&gt;Internationalizing projects used to be complicated. I asked for English and then Portuguese versions, and
I got a system where adding a new language is a tool call and a proof read away.
&lt;strong&gt;A system specific to this one project&lt;/strong&gt;, with its single &lt;code&gt;index.html&lt;/code&gt; copied over
in language subdirectories, &lt;strong&gt;because it&amp;rsquo;s simple, and with LLMs it&amp;rsquo;s now easy to maintain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Testing the skill on real files caught bugs in the HTML.
Adding a third language taught the skill to handle distant and proximate languages.
Each step improved either the thing being checked or the thing doing the checking.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Claude, tell me what needs my attention today</title>
    <link rel="alternate" href="https://withatwist.dev/claude-tell-me-what-needs-my-attention-today.html"/>
    <id>https://withatwist.dev/claude-tell-me-what-needs-my-attention-today.html</id>
    <published>2025-12-23T00:00:00+00:00</published>
    <updated>2026-06-05T15:51:12+00:00</updated>
    <author>
      <name>Tute Costa</name>
    </author>
    <summary type="html">&lt;p&gt;Each morning I open four tabs: Calendar, Gmail, Jira, and Obsidian. I read all, discard low priority emails or calendar events, and &lt;strong&gt;start building a mental picture of what I’ll do that day, and when exactly&lt;/strong&gt;.
For each piece of data I decide whether it’s time sensitive or not, whether I need to prepare beforehand, and whether I should tackle it later (or never).
After warming up my brain, I kick off the actual work.&lt;/p&gt;

&lt;p&gt;I decided &lt;strong&gt;an LLM should do that pre-work instead of my well-rested brain&lt;/strong&gt;. To build such automation I’d practice Claude Code subagents and local MCP servers setup&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Each morning I open four tabs: Calendar, Gmail, Jira, and Obsidian. I read all, discard low priority emails or calendar events, and &lt;strong&gt;start building a mental picture of what I&amp;rsquo;ll do that day, and when exactly&lt;/strong&gt;.
For each piece of data I decide whether it&amp;rsquo;s time sensitive or not, whether I need to prepare beforehand, and whether I should tackle it later (or never).
After warming up my brain, I kick off the actual work.&lt;/p&gt;

&lt;p&gt;I decided &lt;strong&gt;an LLM should do that pre-work instead of my well-rested brain&lt;/strong&gt;. To build such automation I&amp;rsquo;d practice Claude Code subagents and local MCP servers setup,
a good exercise for my new startup, &lt;a href="https://www.railspilot.ai/"&gt;RailsPilot.ai&lt;/a&gt;. So I started creating my &lt;code&gt;/today&lt;/code&gt; Claude Code command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/today&lt;/code&gt; fetches information scattered accross mails, calendar, task manager, and notes, and compiles them into a prioritized task list for the day.
It saves the output to a plain text file like &lt;code&gt;daily_notes/2025-12-23.txt&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s funny to see Claude properly weighing what&amp;rsquo;s worthy of my attention from disparate sources according to natural language explanations, while it juggles different commands to decide what day is today.
&lt;strong&gt;Discovering what&amp;rsquo;s cheap vs challening with LLMs is what I seek, and is also funny to me&lt;/strong&gt;.
December 22nd, 2025 is NOT Sunday, Claude, it&amp;rsquo;s Monday. Wise up!&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/2025-12-23-claude.png" alt="Claude Code organizing my daily tasks" /&gt;&lt;/p&gt;

&lt;p&gt;It first works to define what day is today, then launches three parallel subagents, each responsible for fetching, processing and normalizing data from one source:&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/2025-12-23.png" alt="/today command's flowchart: spawns three parallel subagents for Calendar, Gmail, and Jira" /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;Jira&lt;/em&gt; subagent fetches assigned issues and checks for QA comments that need my attention: my highest priority these end-of-year days.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;Calendar&lt;/em&gt; subagent retrieves today&amp;rsquo;s events and applies priority logic (marks certain family events as low priority reminders, whereas time-sensitive meetings are marked as high priority and with an action item to prepare 15 minutes beforehand).&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;Gmail&lt;/em&gt; subagent reads my inbox, detects newsletters to deprioritize and defines suggested action items for the rest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is designed for efficiency: &lt;strong&gt;raw API responses are contained within each subagent&amp;rsquo;s context window and discarded after processing&lt;/strong&gt;, so only compact JSON summaries flow back to the main agent.
This keeps the context clean and &lt;strong&gt;allows each source to fail independently&lt;/strong&gt; without breaking the entire command.
It will also let me enable only relevant MCPs per subagent, another context window optimization I didn&amp;rsquo;t yet need.&lt;/p&gt;

&lt;p&gt;Each subagent normalizes its data into a common task schema with fields like &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;source&lt;/code&gt;, &lt;code&gt;priority&lt;/code&gt;, &lt;code&gt;due date&lt;/code&gt;, &lt;code&gt;URL&lt;/code&gt;, and &lt;code&gt;action item&lt;/code&gt;. Low-priority items include a reason why. &lt;strong&gt;This normalization allows disparate data pieces to be compared and sorted&lt;/strong&gt;. When all subagents return their results to the orchestrator agent, it merges everything into a single list sorted by priority and time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The final output is plain text designed for quick scanning top to bottom&lt;/strong&gt;, with key details, URL and action item after each title.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;Daily Tasks - December 23, 2025
==============================

• [DEV-450] Enable PWA On Select Pages
  - Status: IN QA
  - Action: Respond to QA comments from David regarding errors on refresh
  - URL: https://client.atlassian.net/browse/DEV-450

• Your Documents are now ready for Reservation ID: 123456
  - From: Provider &amp;lt;^DONOTREPLY@provider.com&amp;gt;
  - Action: download and print documents, complete forms
  - URL: https://mail.google.com/mail/u/0/#inbox/123456789

• [DEV-430] Landing Page N+1s
  - Status: IN QA
  - Action: No QA feedback yet
  - URL: https://client.atlassian.net/browse/DEV-430

• Kids visit Granny - 3:00 PM to 7:00 PM
  - Note: Family reminder
  - URL: https://www.google.com/calendar/event?eid=eideideideideideideid

---
Generated at 2025-12-23 09:30:00
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And, instead of sifting through tabs, I can go from cup of coffee straight to my top priority for the day.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How I use AI agents to code new features</title>
    <link rel="alternate" href="https://withatwist.dev/how-i-use-ai-agents-to-code-new-features.html"/>
    <id>https://withatwist.dev/how-i-use-ai-agents-to-code-new-features.html</id>
    <published>2025-02-20T00:00:00+00:00</published>
    <updated>2026-06-05T15:51:12+00:00</updated>
    <author>
      <name>Tute Costa</name>
    </author>
    <summary type="html">&lt;p&gt;I wrote about how Cursor&amp;rsquo;s AI agent helped me build a high quality new feature in
Rails, without much &amp;ldquo;prompt engineering&amp;rdquo; getting in the way.&lt;/p&gt;

&lt;p&gt;You can find it in my employer&amp;rsquo;s blog:
&lt;a href="https://buoy.blog/2025/02/11/how-i-use-ai-agents-to-code-new-features.html"&gt;&amp;ldquo;How I use AI agents to code new features&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
</summary>
    <content type="html">&lt;p&gt;I wrote about how Cursor&amp;rsquo;s AI agent helped me build a high quality new feature in
Rails, without much &amp;ldquo;prompt engineering&amp;rdquo; getting in the way.&lt;/p&gt;

&lt;p&gt;You can find it in my employer&amp;rsquo;s blog:
&lt;a href="https://buoy.blog/2025/02/11/how-i-use-ai-agents-to-code-new-features.html"&gt;&amp;ldquo;How I use AI agents to code new features&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Writing Architecture Documents (for developers)</title>
    <link rel="alternate" href="https://withatwist.dev/writing-architecture-documents-for-developers.html"/>
    <id>https://withatwist.dev/writing-architecture-documents-for-developers.html</id>
    <published>2022-03-31T00:00:00+00:00</published>
    <updated>2026-06-05T15:51:12+00:00</updated>
    <author>
      <name>Tute Costa</name>
    </author>
    <summary type="html">&lt;p&gt;Our colleague Martin was about to start working on a small-scale feature, an addition to a module
that wasn’t open for extension and couldn’t easily support it.&lt;/p&gt;

&lt;p&gt;He could &lt;strong&gt;shoehorn his use case on top of existing architecture without affecting others much
or lay a more robust foundation&lt;/strong&gt; over which he’d implement his use case. This could also help fix long-standing bugs and enable the implementation of new features that we foresee in our next two years (but would be hard to add now).
In other words, “make the change easy, then make the easy change”.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Our colleague Martin was about to start working on a small-scale feature, an addition to a module
that wasn’t open for extension and couldn’t easily support it.&lt;/p&gt;

&lt;p&gt;He could &lt;strong&gt;shoehorn his use case on top of existing architecture without affecting others much
or lay a more robust foundation&lt;/strong&gt; over which he&amp;rsquo;d implement his use case. This could also help fix long-standing bugs and enable the implementation of new features that we foresee in our next two years (but would be hard to add now).
In other words, &amp;ldquo;make the change easy, then make the easy change&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;We are a 20-people team organized into three pods (each
with a Product Manager, a QA tester, and about three developers), designers, and leadership roles.
The three pod structure helped us &lt;strong&gt;work without needing to have the context of the whole application&lt;/strong&gt; in mind
but made us &lt;strong&gt;need to sync up whenever a decision would affect others&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Martin postponed his solution in favor of determining a better architecture.
He needed to write up a document to share ideas with everyone,
ensuring we covered every pod’s needs and addressed the comparatively minor feature that led to these conversations.&lt;/p&gt;

&lt;p&gt;Martin wanted the document to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;be &lt;strong&gt;succinct&lt;/strong&gt;, so everybody reads it, can share feedback, and signs off on
&lt;strong&gt;–while also adding much detail&lt;/strong&gt; to ensure no scenario (current or future) is left unattended&lt;/li&gt;
&lt;li&gt;use &lt;strong&gt;general language&lt;/strong&gt; so his Product Manager can follow it
&lt;strong&gt;while also using technical jargon&lt;/strong&gt;, so his CTO will know precisely where we are heading&lt;/li&gt;
&lt;li&gt;be &lt;strong&gt;quick&lt;/strong&gt;, so he can get going with his solution
&lt;strong&gt;while also letting the document sit for days&lt;/strong&gt; so
people in different time zones share their feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How could he write the document with such competing goals? Martin and I paired on it many times,
took notes, shared with the team, and wrote what worked well for us.&lt;/p&gt;

&lt;h1&gt;Definitions&lt;/h1&gt;

&lt;p&gt;First, Martin defined an objective, an audience, and a desirable trait for the document:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objective&lt;/strong&gt;: Efficiently communicate the problems and goals for the audience
to discuss and support our decision, ideally without the need for meetings.
Many people will read it many times, so we’ll take the time to make it clear and succinct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audience&lt;/strong&gt;: For this case, our Director of Engineering. A single person, which in turn
helps define the level of detail, tone, and deadline for the document.
Interested developers and technically inclined Product Managers should be able to follow along a document intended for our Director
(or know whom to ask for clarifications).&lt;br&gt;
Even if more people are deciders for the solution, it will help the writer to have
a single person in mind to whom he’s writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desirable&lt;/strong&gt;: Discuss at least two alternative solutions for the problem,
outlining their pros and cons.
What would the solution look like if we had all the time in the world?
Or double our team size? Or only half of our team size?
What if we needed to get something out in two weeks?&lt;/p&gt;

&lt;h1&gt;The document’s structure&lt;/h1&gt;

&lt;p&gt;Most developers at Epion have much less experience writing documents than writing code. Martin got a case of blank page block.
How could he put in a couple of sheets of paper everything we discussed over lunch and on several calls,
looking both at the short and long term?
There were still open questions and even unknown unknowns!&lt;/p&gt;

&lt;p&gt;I suggested starting from a template defining a structure.
&lt;strong&gt;How should an Architecture Document look when skimming from afar?&lt;/strong&gt;
We wrote that down with some generic content that we’d iterate on for the feature and project at hand.&lt;/p&gt;

&lt;p&gt;The blueprint with dummy content looked like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;Bariloche (a short &amp;ldquo;catchy&amp;rdquo; name)&lt;/h1&gt;

&lt;h2&gt;High-level overview&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What&lt;/strong&gt; we want (in order of priority):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A great cost/benefit ratio (weigh up requirements and available resources)&lt;/li&gt;
&lt;li&gt;Seize a good risk/value ratio (some risk is acceptable for great value; what’s our aim and tolerance?)&lt;/li&gt;
&lt;li&gt;Make our teams happier (what specific teams, and what can we improve for them?)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not a fourth! That’s enough; we shall define the top ones only.
Also ok: &amp;ldquo;we don’t want to&amp;quot;s: we don’t want to continue seeing a current architecture problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who&lt;/strong&gt; will participate in this decision, who will approve it, and who are responsible for executing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When&lt;/strong&gt;: a timeline and the &amp;quot;why&amp;rdquo; behind each deadline.&lt;/p&gt;

&lt;p&gt;Top-down overview. We&amp;rsquo;ll achieve this by doing first some work that makes our pods
and their stakeholders happy (the feature at the start of this story).
We&amp;rsquo;ll also lay down foundations for our new architecture, enabling
the fixes for long-standing bugs and paving the road for features on our horizon.&lt;/p&gt;

&lt;h2&gt;Alternative A&lt;/h2&gt;

&lt;h3&gt;Description&lt;/h3&gt;

&lt;p&gt;Detailed description, supported with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ERD/class diagrams&lt;/li&gt;
&lt;li&gt;Database migrations (maybe a link, but nice to see them verbatim here to see not only entities but also their attributes and types)&lt;/li&gt;
&lt;li&gt;Implementation notes&lt;/li&gt;
&lt;li&gt;Use cases and sample data (could be a link to a GitHub spike PR, a linked document, or a block of code within).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It&amp;rsquo;s not a solution to apply as-is,
but detailed enough that developers can “run it” in their minds and
provide more specific feedback, saving time in future code reviews.&lt;/p&gt;

&lt;p&gt;List of features enabled by the design and problems prevented by it.&lt;/p&gt;

&lt;h2&gt;Alternative B&lt;/h2&gt;

&lt;h3&gt;Description&lt;/h3&gt;

&lt;p&gt;&amp;hellip;&lt;/p&gt;

&lt;h2&gt;Comparison&lt;/h2&gt;

&lt;p&gt;Pros and Cons of considered alternatives.&lt;/p&gt;

&lt;h2&gt;Timeline&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;First Quarter&lt;/strong&gt;: We&amp;rsquo;ll do the work that triggered this conversation. Pod and PM will be happy and timely get what they want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second Quarter&lt;/strong&gt;: Developers will have a better architecture to more easily implement future work in our pipeline, such as A, B, and C.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third Quarter&lt;/strong&gt;: We&amp;rsquo;ll delete legacy implementations and run 100% on the design we want.&lt;/p&gt;

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

&lt;p&gt;Described objectives will be met (expand this).
We can’t identify additional risks (consider running &lt;a href="https://medium.com/paypal-tech/pre-mortem-technically-working-backwards-1724eafbba02"&gt;&amp;ldquo;pre-mortems&amp;rdquo;&lt;/a&gt; to find more).
We’ll be in a better place to implement future work without neglecting our short-term commitments.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Final thoughts&lt;/h1&gt;

&lt;p&gt;One goal is to &lt;strong&gt;avoid discussions until we have a mature draft with concrete alternatives&lt;/strong&gt;.
Discussions expand the space of possibilities (&amp;ldquo;design by committee&amp;rdquo;), while writing reduces it to its most essential components.
Consensus means no ownership. But we do want to hear everyone’s feedback before making the decision.&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/2021-10-21-homers-car.jpg" alt="Design by committee project" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In an Architecture Document we should use a tone different from what we are used to during code reviews&lt;/strong&gt;:
in code review we tend to ask rather than prescribe, use open-ended questions, and ask for early feedback.
We&amp;rsquo;ll first avoid such early discussion, only describing a path forward. Discussions will come later.&lt;/p&gt;

&lt;p&gt;With Architecture Documents we can implement our near-term work while
aligning ourselves with the long-term vision for Epion Products.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;small&gt;I took some ideas in this article from:&lt;/small&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://review.firstround.com/square-defangs-difficult-decisions-with-this-system-heres-how"&gt;Square’s system to make decisions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I first read about &amp;ldquo;Pre-Mortems&amp;rdquo; in &amp;ldquo;Thinking Fast and Slow&amp;rdquo; by Daniel-Kahneman (on our Epion Book Club)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/b0rk/status/1262415197345636353"&gt;Julia Evans&amp;rsquo; zine on writing for a single person&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Mystery Guest Development Edition</title>
    <link rel="alternate" href="https://withatwist.dev/mystery-guest-development-edition.html"/>
    <id>https://withatwist.dev/mystery-guest-development-edition.html</id>
    <published>2021-05-10T00:00:00+00:00</published>
    <updated>2026-06-05T15:51:12+00:00</updated>
    <author>
      <name>Sebastian Armano</name>
    </author>
    <summary type="html">&lt;p&gt;Mystery Guest is the name of an anti-pattern that often appear in tests. In
short, it is caused by non explicitly declaring or naming a value, which
is tested over that faulty declaration.  &lt;strong&gt;The issue is not apparent at
first, as the test is created at the same time as the fixture or
factory that supports it&lt;/strong&gt;. Eventually, when a change is needed in that support
object to test something else, the change unintentionally breaks the first
test.&lt;/p&gt;

&lt;p&gt;For a test which verifies that the &lt;code&gt;full_name&lt;/code&gt; of a user is the combination of
&lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt;, those two properties need to appear explicitly on
the test setup. Even if you have &lt;code&gt;user&lt;/code&gt; factory, you are not testing the
factory, but &lt;em&gt;your own&lt;/em&gt; &lt;code&gt;user&lt;/code&gt; with &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt;.  If the users
in your application also need, say, an address not being tested in
this example, the factory can provide that.&lt;/p&gt;

&lt;p&gt;So the question arises: &lt;strong&gt;are tests the only ones affected by this
anti-pattern?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</summary>
    <content type="html">&lt;p&gt;Mystery Guest is the name of an anti-pattern that often appear in tests. In
short, it is caused by non explicitly declaring or naming a value, which
is tested over that faulty declaration.  &lt;strong&gt;The issue is not apparent at
first, as the test is created at the same time as the fixture or
factory that supports it&lt;/strong&gt;. Eventually, when a change is needed in that support
object to test something else, the change unintentionally breaks the first
test.&lt;/p&gt;

&lt;p&gt;For a test which verifies that the &lt;code&gt;full_name&lt;/code&gt; of a user is the combination of
&lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt;, those two properties need to appear explicitly on
the test setup. Even if you have &lt;code&gt;user&lt;/code&gt; factory, you are not testing the
factory, but &lt;em&gt;your own&lt;/em&gt; &lt;code&gt;user&lt;/code&gt; with &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt;.  If the users
in your application also need, say, an address not being tested in
this example, the factory can provide that.&lt;/p&gt;

&lt;p&gt;So the question arises: &lt;strong&gt;are tests the only ones affected by this
anti-pattern?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s see an example.&lt;/p&gt;

&lt;p&gt;In our application, we had a &lt;code&gt;CheckIn&lt;/code&gt; model and a associated &lt;code&gt;Progress&lt;/code&gt;
to record when the each step of a check-in has been completed. &lt;strong&gt;We
want to calculate, among other things, the duration of each check-in for
reporting purposes&lt;/strong&gt;. We had something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/check_in.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckIn&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;

  &lt;span class="n"&gt;before_create&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/progress.rb&lt;/span&gt;
&lt;span class="no"&gt;Class&lt;/span&gt; &lt;span class="no"&gt;Progress&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:check_in&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;duration&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;duration&lt;/code&gt; method in &lt;code&gt;Progress&lt;/code&gt; is the interesting one. We didn&amp;rsquo;t need to
use the &lt;code&gt;CheckIn&lt;/code&gt; &lt;code&gt;created_at&lt;/code&gt; field because a &lt;code&gt;Progress&lt;/code&gt; was created at the
same time. So, to simplify and optimize, we used the &lt;code&gt;Progress&lt;/code&gt; &lt;code&gt;created_at&lt;/code&gt;
method instead. &lt;strong&gt;There is no issue whatsoever with this approach. Or is
there?&lt;/strong&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;After some time, we decided to include events happening &lt;em&gt;before&lt;/em&gt; the patient
arrives to the practice, which is before the check-in.&lt;/p&gt;

&lt;p&gt;We created a new model called &lt;code&gt;Engagement&lt;/code&gt;. As we still wanted to keep track of
steps completed before and during the check-in, we associated our &lt;code&gt;Progress&lt;/code&gt; to
the Engagement which we moved up from the &lt;code&gt;CheckIn&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/engagement.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Engagement&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:check_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;

  &lt;span class="n"&gt;before_create&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/check_in.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckIn&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:engagement&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/progress.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Progress&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:engagement&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;duration&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You have probably already seen the problem. Progresses are now sometimes created
long before the check-in starts. In some cases, &lt;em&gt;days&lt;/em&gt; before.  And since then,
our calculations of check-in &lt;code&gt;duration&lt;/code&gt; started failing.  And that is not the
biggest problem. &lt;strong&gt;The main issue is how hard this is to detect.&lt;/strong&gt;  Tests are
green, and there&amp;rsquo;s no clear indication that the calculations are wrong until you
see the actual numbers.&lt;/p&gt;

&lt;p&gt;We thought we knew all our dependencies, but &lt;strong&gt;a mysterious guest appeared!&lt;/strong&gt;  We
assumed that progresses would always be &lt;code&gt;check_in&lt;/code&gt; progresses, but that&amp;rsquo;s not
true anymore. Old &lt;code&gt;check_in&lt;/code&gt; progresses are now &lt;code&gt;engagement&lt;/code&gt; ones.
Once again, we trusted the underlying object supporting our assumptions, but it
changed on us.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;The fix is arguably even more interesting than the bug. As a first step, we
specify that we want &lt;code&gt;check_in.created_at&lt;/code&gt; timestamp and not the &lt;code&gt;progress&lt;/code&gt;
one. Also, as a &lt;code&gt;progress&lt;/code&gt; now is associated with an &lt;code&gt;Engagement&lt;/code&gt;, we can
change the name of the method to specify what we are talking about.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/progress.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Progress&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:engagement&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_in_duration&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;created_at&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, method name and implementation are telling us something else. All the
references to &lt;code&gt;check_in&lt;/code&gt; indicate this method probably suffers from &amp;ldquo;feature
envy&amp;rdquo;, and should be in the &lt;code&gt;CheckIn&lt;/code&gt; object instead of here. &lt;strong&gt;In our way of
fixing an issue we found a better design for our code as well!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the final version:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/engagement.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Engagement&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:check_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;

  &lt;span class="n"&gt;before_create&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/check_in.rb&lt;/span&gt;
&lt;span class="no"&gt;CheckIn&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:engagement&lt;/span&gt;

  &lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="ss"&gt;:completed_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: :progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;prefix: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;duration&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;completed_timestamp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;progress_completed_timestamp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;table class="rouge-table"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="rouge-gutter gl"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
&lt;/pre&gt;&lt;/td&gt;&lt;td class="rouge-code"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# models/progress.rb&lt;/span&gt;
&lt;span class="no"&gt;Class&lt;/span&gt; &lt;span class="no"&gt;Progress&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:engagement&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_in_completed_timestamp&lt;/span&gt;
    &lt;span class="n"&gt;check_in_completed_at&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In summary, there were two main reasons for a &lt;em&gt;development mystery
guest&lt;/em&gt; here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We trusted&lt;/strong&gt; that objects supporting our code assumptions wouldn&amp;rsquo;t change on us.
And because of that, we didn&amp;rsquo;t specify the information needed from them. (The
same happens during testing when we trust fixtures or factories to have the data
for us to pass the test, instead of declaring it during setup).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;We optimized too early&lt;/strong&gt;. It is simpler to call a method in the
current object than to ask for the information to some other one. But even if
simpler, it may not be correct with future changes in the code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;Avoid assuming that the information depending on other objects will always be
as correct as it is today&lt;/strong&gt;.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Always specify what you need. And forget about early &amp;ldquo;optimizations&amp;rdquo;. Do them
when they make sense and are needed.  That&amp;rsquo;s how you make sure you prevent
mystery guests.&lt;/p&gt;
</content>
  </entry>
</feed>
