<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>thomas vilhena</title>
		<description>Thoughts on Software Development</description>
		<link>https://thomasvilhena.com</link>
		<atom:link href="https://thomasvilhena.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>This blog is on the Small Web</title>
				<description>&lt;p&gt;I was browsing Hacker News yesterday and saw a post titled &lt;a href=&quot;https://news.ycombinator.com/item?id=47410542&quot;&gt;Kagi Small Web&lt;/a&gt; ranking high on the front page. Curiosity got the better of me, so I clicked through. I ended up spending some time there just jumping through random posts comprised of actually interesting stuff written by real people, not the usual SEO-optimized or AI “slop” we see everywhere now.&lt;/p&gt;

&lt;p&gt;Then I did a bit of digging. It turns out, this blog is on that list too 🙂&lt;/p&gt;

&lt;h1 id=&quot;what-is-this-list&quot;&gt;What is this list?&lt;/h1&gt;
&lt;p&gt;I went over to their &lt;a href=&quot;https://github.com/kagisearch/smallweb&quot;&gt;GitHub repository&lt;/a&gt; to see what was going on. As of today, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smallweb.txt&lt;/code&gt; file is comprised of &lt;strong&gt;34,492&lt;/strong&gt; blogs and personal websites. It’s basically a very large, curated index of a (more?) “human” internet.&lt;/p&gt;

&lt;p&gt;If you’re wondering how a site gets included, they have a &lt;a href=&quot;https://github.com/kagisearch/smallweb?tab=readme-ov-file#%EF%B8%8F-guidelines-for-site-inclusion-to-the-list-%EF%B8%8F&quot;&gt;specific set of rules&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Non-Commercial:&lt;/strong&gt; No intrusive ads, paywalls, or heavy affiliate marketing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Human-Centric:&lt;/strong&gt; Absolutely no AI-generated or LLM “spam” content.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Technical:&lt;/strong&gt; You must have a valid RSS or Atom feed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Recent-ish:&lt;/strong&gt; The blog needs at least one post in the last 12 months to stay in the index.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Personal:&lt;/strong&gt; It favors personal diaries, niche technical deep-dives, and independent essays over corporate blogs or newsletters (Substack seems like a no-go).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Turns out, these criteria favor both better content and a better experience, exactly what I value.&lt;/p&gt;

&lt;h1 id=&quot;seven-years-of-zero-maintenance&quot;&gt;Seven years of “Zero Maintenance”&lt;/h1&gt;
&lt;p&gt;I actually never submitted my blog to be included. It likely got picked up because I’ve been running this blog for seven years now, since 2019. I use &lt;strong&gt;Jekyll&lt;/strong&gt; - don’t know if it’s still a thing, but it works.&lt;/p&gt;

&lt;p&gt;The best part? Jekyll generates an RSS feed out of the box, which turned out to be one of the requirements for getting indexed by Kagi. I host everything on &lt;a href=&quot;https://github.com/TCGV/blog&quot;&gt;GitHub Pages&lt;/a&gt;, which I highly recommend. It’s free, requires zero maintenance time, and it’s surprisingly robust. It can handle a “Hacker News hug of death” without breaking a sweat whenever one of my posts accidentally hits the front page.&lt;/p&gt;

&lt;p&gt;If you’ve been thinking about starting your own blog and you have some technical skills, you don’t need a complex setup / CMS. You could literally just &lt;a href=&quot;https://github.com/TCGV/blog&quot;&gt;clone my repo&lt;/a&gt;, restyle the layout, and set up your own domain on GitHub Pages for free.&lt;/p&gt;

&lt;h1 id=&quot;is-the-small-web-actually-useful&quot;&gt;Is the small web actually useful?&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://news.ycombinator.com/item?id=47410542&quot;&gt;original HN thread&lt;/a&gt; had some mixed feelings. A few people were underwhelmed by the current implementation, calling it “more like a curated blog ring than a discovery engine for the broader indie web.” Others were more optimistic, acknowledging that it’s a “good idea with a decent foundation.”&lt;/p&gt;

&lt;p&gt;Personally, I just appreciate the small bit of recognition. In a world where every search result feels like it was written by a bot to sell me a mattress, it’s nice to be officially part of the “Small Web”, even more since I didn’t subscribe to be on the list myself.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Cheers! 🍻&lt;/p&gt;
</description>
				<pubDate>Wed, 18 Mar 2026 16:00:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2026/03/this-blog-is-on-the-small-web</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2026/03/this-blog-is-on-the-small-web</guid>
			</item>
		
			<item>
				<title>Craftsmanship coding and the five stages of grief</title>
				<description>&lt;p&gt;If you’ve been reading recent Hacker News threads, you’ve probably noticed a recurring tone: a recurring mourning for “craftsmanship” in software, for the clay-in-hands feeling of shaping code line by line.&lt;/p&gt;

&lt;p&gt;Here’s some evidence:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=46926245&quot;&gt;“We mourn our craft”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=46881264&quot;&gt;“I miss thinking hard”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=46960675&quot;&gt;“I started programming when I was 7… the thing I loved has changed”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;And, of course, existential dread about &lt;a href=&quot;https://news.ycombinator.com/item?id=46933067&quot;&gt;“slop” eating the internet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we borrow the “five stages of grief” as a metaphor, it feels like part of our industry is hovering around &lt;strong&gt;depression&lt;/strong&gt;. Not because people are lacking resilience, but because the change is structural, not cosmetic. And structural change hits identity.&lt;/p&gt;

&lt;p&gt;The next stage is &lt;strong&gt;acceptance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not “AI will code everything,” but “AI will code most of it”, and in many teams, it already does. But what does that mean? Simply put, software engineers will delegate most tasks to AI.&lt;/p&gt;

&lt;p&gt;Here’s some truth about professional software:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Most developer time isn’t cathedral-building. It’s digital plumbing.&lt;/p&gt;

  &lt;p&gt;It’s reading code, changing code, moving data between systems, integrating APIs, handling edge cases, and keeping production stable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s exactly where “agentic coding” is already meaningfully useful, because it’s fast at the repetitive, low-cognition parts, and when you can verify outputs/diffs (with your own eyes) cheaply. So why not use it in this context?&lt;/p&gt;

&lt;p&gt;But bear in mind: most tasks don’t mean most value. So at a minimum treat agentic coding as a great tool to delegate lower-value tasks so that you can spend more time on higher-value work.&lt;/p&gt;

&lt;h1 id=&quot;a-practical-ladder-most-to-least-delegable&quot;&gt;A practical ladder (most to least delegable)&lt;/h1&gt;

&lt;table class=&quot;basic-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Work type&lt;/th&gt;
      &lt;th&gt;What agents are good at&lt;/th&gt;
      &lt;th&gt;Your job stays&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;CRUD&lt;/td&gt;
      &lt;td&gt;patterns, scaffolding, consistency&lt;/td&gt;
      &lt;td&gt;schema/constraints, tests, review&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Data plumbing / transfer&lt;/td&gt;
      &lt;td&gt;adapters, ETL-ish glue, client code&lt;/td&gt;
      &lt;td&gt;contracts, failure modes, monitoring&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Simple transformations / integrations&lt;/td&gt;
      &lt;td&gt;deterministic changes, refactors&lt;/td&gt;
      &lt;td&gt;golden tests, invariants, change safety&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Algorithms (well-specified)&lt;/td&gt;
      &lt;td&gt;standard approaches + edge handling&lt;/td&gt;
      &lt;td&gt;spec, complexity targets, property tests&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Architecture&lt;/td&gt;
      &lt;td&gt;exploring options, drafting designs&lt;/td&gt;
      &lt;td&gt;making implicit constraints explicit&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;High-assurance software&lt;/td&gt;
      &lt;td&gt;helping with review and test drafts&lt;/td&gt;
      &lt;td&gt;ownership, compliance, zero-tolerance gates&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;There are many levels of delegation; it isn’t (and shouldn’t be) all-or-nothing. The less complex, less sensitive, and more reversible a task is, the more you can delegate the bulk of the work and let the agent drive. At the other end of the spectrum: complex or high-stakes work where failures are costly and reversals are painful, you keep your hands on the wheel.&lt;/p&gt;

&lt;h1 id=&quot;what-ive-experienced-in-real-projects&quot;&gt;What I’ve experienced in real projects&lt;/h1&gt;

&lt;p&gt;When the codebase has clear boundaries and coherent architecture, agents can be genuinely productive. When it’s spaghetti code, agents degrade quickly and produce mediocre output, because the system itself has weak signals.&lt;/p&gt;

&lt;p&gt;Starting projects from scratch with agentic tools is also possible, but usually harder. You can make it work, but only if you provide much stronger specs. The broader and more ambiguous the task, the worse the output variance.&lt;/p&gt;

&lt;p&gt;In other words, agents excel when scope is narrower, objectives are explicit, and review is cheap. The best use cases are tasks you’d feel comfortable coding yourself: you can write clear instructions, verify results, and do small adjustments before shipping.&lt;/p&gt;

&lt;p&gt;That’s where the efficiency gains are real.&lt;/p&gt;

&lt;h1 id=&quot;so-how-to-stay-ahead-in-an-agentic-world&quot;&gt;So, how to stay ahead in an agentic world&lt;/h1&gt;

&lt;p&gt;It isn’t about typing faster. It’s about moving craftsmanship upstream.&lt;/p&gt;

&lt;p&gt;When agents write more of the code, the “handmade” part doesn’t disappear, it relocates. Craft becomes the ability to shape intent into constraints, turn ambiguity into decisions, and build systems where correctness is the default, not a happy accident.&lt;/p&gt;

&lt;p&gt;Acceptance is not surrender. It’s admitting that most work is plumbing, and choosing to spend your human attention where it compounds: on higher-value, higher-stakes tasks.&lt;/p&gt;

&lt;p&gt;So I say embrace the new paradigm agentic tools enable, where specification and intent are ever more important, low-complexity tasks delegated in bulk, and we can leverage our time to focus on higher-level challenges.&lt;/p&gt;
</description>
				<pubDate>Fri, 13 Feb 2026 15:00:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2026/02/craftsmanship-coding-five-stages-of-grief</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2026/02/craftsmanship-coding-five-stages-of-grief</guid>
			</item>
		
			<item>
				<title>Revisiting ChatGPT’s financial advice, 15 months later</title>
				<description>&lt;p&gt;In Oct/2024 I asked ChatGPT for a portfolio to endure a messy world (original post &lt;a href=&quot;https://thomasvilhena.com/2024/10/financial-advice-from-chatgpt&quot;&gt;here&lt;/a&gt;). At that time I expected the Israel–Palestine conflict (on top of Russia–Ukraine) to be the main driver of financial uncertainty in the coming months.&lt;/p&gt;

&lt;p&gt;Fifteen months later, the conflicts are still there, but the volatility came from a different menu: U.S. surprises, Trump’s tariff war, a U.S. strike on an Iranian nuclear facility, and most recently Maduro’s capture.&lt;/p&gt;

&lt;p&gt;This post is my promised check-in: what would have happened if I’d followed ChatGPT’s financial advice? I re-ran the original constraints using a 2024 model snapshot, translated the output into a real ETF portfolio, and measured the results.&lt;/p&gt;

&lt;h1 id=&quot;the-portfolio-setup&quot;&gt;The portfolio setup&lt;/h1&gt;

&lt;p&gt;The original post suggested a broad allocation. To make it testable, I re-ran a prompt in the old GPT-4o model (via OpenAI’s API, specifically &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gpt-4o-2024-08-06&lt;/code&gt; to avoid lookahead bias) to generate a concrete, investable portfolio, using the exact constraints from that post.&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;prompt&lt;/span&gt;&lt;/p&gt;

  &lt;p&gt;Construct a portfolio of stock indices, US bonds, corporate bond indices, and commodities, adhering to the following percentages:&lt;/p&gt;

  &lt;p&gt;50% Equities: Diversify across geographies and sectors (some growth-oriented, some defensive).&lt;/p&gt;

  &lt;p&gt;30% Bonds: Split between safe-haven government bonds and investment-grade corporate bonds.&lt;/p&gt;

  &lt;p&gt;20% Commodities &amp;amp; Alternative Investments: This portion can include gold, oil, and possibly some real estate or infrastructure investments that are less correlated with traditional assets.&lt;/p&gt;

  &lt;p&gt;Suggest only assets accessible to an individual investor via a US investment account.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;Here’s the generated response:&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;response&lt;/span&gt;&lt;/p&gt;

  &lt;p&gt;Creating a diversified portfolio as per your specifications involves selecting specific ETFs and index funds that are accessible to retail investors. Here’s a suggested portfolio:&lt;/p&gt;

  &lt;h3 id=&quot;equities&quot;&gt;50% Equities&lt;/h3&gt;

  &lt;p&gt;&lt;strong&gt;US Equities (25%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;SPDR S&amp;amp;P 500 ETF Trust (SPY)&lt;/strong&gt;: Covers large-cap U.S. equities.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;International Equities (15%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;iShares MSCI ACWI ex U.S. ETF (ACWX)&lt;/strong&gt;: Provides exposure to large and mid-cap stocks outside the U.S.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Emerging Markets (10%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Vanguard FTSE Emerging Markets ETF (VWO)&lt;/strong&gt;: Targets growth-potential markets.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;bonds&quot;&gt;30% Bonds&lt;/h3&gt;

  &lt;p&gt;&lt;strong&gt;US Government Bonds (15%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;iShares 7-10 Year Treasury Bond ETF (IEF)&lt;/strong&gt;: Focuses on U.S. Treasury bonds, providing a safe-haven investment.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Corporate Bonds (15%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;iShares iBoxx $ Investment Grade Corporate Bond ETF (LQD)&lt;/strong&gt;: Offers exposure to investment-grade U.S. corporate bonds.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;commodities--alternative-investments&quot;&gt;20% Commodities &amp;amp; Alternative Investments&lt;/h3&gt;

  &lt;p&gt;&lt;strong&gt;Gold (10%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;SPDR Gold Trust (GLD)&lt;/strong&gt;: Direct exposure to gold prices.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Oil (5%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;United States Oil Fund (USO)&lt;/strong&gt;: Tracks the daily price movements of West Texas Intermediate (WTI) light, sweet crude oil.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Real Estate &amp;amp; Infrastructure (5%)&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Vanguard Real Estate ETF (VNQ)&lt;/strong&gt;: Provides exposure to U.S. real estate investment trusts (REITs).&lt;/li&gt;
  &lt;/ul&gt;

  &lt;h3 id=&quot;considerations&quot;&gt;Considerations&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Diversification&lt;/strong&gt;: The selection covers multiple geographies, sectors, and asset classes, reducing risk through diversification.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;: All assets are available through major U.S. brokerages.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Liquidity&lt;/strong&gt;: ETFs and index funds offer liquidity, making it easier to enter and exit positions.&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Risk Tolerance&lt;/strong&gt;: Adjust weights as needed based on individual risk tolerance and investment horizon.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;Before investing, consider consulting with a financial advisor to tailor the portfolio to your personal financial situation and goals.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;This gave me a realistic, investable snapshot of “what ChatGPT would have done” at the time.&lt;/p&gt;

&lt;h1 id=&quot;the-results-oct-4-2024--jan-27-2026&quot;&gt;The results (Oct 4, 2024 → Jan 27, 2026)&lt;/h1&gt;

&lt;p&gt;A couple of days ago I pulled the adjusted prices (dividends, splits, capital gains) from Yahoo Finance (e.g., &lt;a href=&quot;https://finance.yahoo.com/quote/GLD/history/?period1=1728000000&amp;amp;period2=1728086400&quot;&gt;GLD history&lt;/a&gt;) and calculated the ROI for each sleeve.&lt;/p&gt;

&lt;table class=&quot;basic-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Asset&lt;/th&gt;
      &lt;th&gt;Weight&lt;/th&gt;
      &lt;th&gt;2024-10-04&lt;/th&gt;
      &lt;th&gt;2026-01-27&lt;/th&gt;
      &lt;th&gt;ROI&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;SPDR S&amp;amp;P 500 ETF Trust (SPY)&lt;/td&gt;
      &lt;td&gt;25%&lt;/td&gt;
      &lt;td&gt;564.43&lt;/td&gt;
      &lt;td&gt;695.49&lt;/td&gt;
      &lt;td&gt;23.22%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;iShares MSCI ACWI ex U.S. ETF (ACWX)&lt;/td&gt;
      &lt;td&gt;15%&lt;/td&gt;
      &lt;td&gt;54.59&lt;/td&gt;
      &lt;td&gt;71.97&lt;/td&gt;
      &lt;td&gt;31.84%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vanguard FTSE Emerging Markets ETF (VWO)&lt;/td&gt;
      &lt;td&gt;10%&lt;/td&gt;
      &lt;td&gt;46.56&lt;/td&gt;
      &lt;td&gt;57.64&lt;/td&gt;
      &lt;td&gt;23.80%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;iShares 7-10 Year Treasury Bond ETF (IEF)&lt;/td&gt;
      &lt;td&gt;15%&lt;/td&gt;
      &lt;td&gt;92.01&lt;/td&gt;
      &lt;td&gt;95.98&lt;/td&gt;
      &lt;td&gt;4.31%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;iShares iBoxx $ Investment Grade Corporate Bond ETF (LQD)&lt;/td&gt;
      &lt;td&gt;15%&lt;/td&gt;
      &lt;td&gt;105.48&lt;/td&gt;
      &lt;td&gt;110.81&lt;/td&gt;
      &lt;td&gt;5.05%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SPDR Gold Trust (GLD)&lt;/td&gt;
      &lt;td&gt;10%&lt;/td&gt;
      &lt;td&gt;245.00&lt;/td&gt;
      &lt;td&gt;476.10&lt;/td&gt;
      &lt;td&gt;94.33%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;United States Oil Fund (USO)&lt;/td&gt;
      &lt;td&gt;5%&lt;/td&gt;
      &lt;td&gt;76.35&lt;/td&gt;
      &lt;td&gt;75.66&lt;/td&gt;
      &lt;td&gt;-0.90%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vanguard Real Estate ETF (VNQ)&lt;/td&gt;
      &lt;td&gt;5%&lt;/td&gt;
      &lt;td&gt;90.63&lt;/td&gt;
      &lt;td&gt;90.39&lt;/td&gt;
      &lt;td&gt;-0.26%&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Portfolio result:&lt;/strong&gt; +23.74% over 15 months. Not bad.&lt;/p&gt;

&lt;h1 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h1&gt;

&lt;p&gt;Net result: the portfolio held up. Most of it came from a surprisingly good gold run, with stocks doing their job and everything else mostly hovering. That’s encouraging, since diversification did its job, and also a warning, because one lucky ingredient can dominate the outcome.&lt;/p&gt;

&lt;p&gt;So: would you trust an AI to build your portfolio, or are you already using it (even if just as a second opinion)?&lt;/p&gt;
</description>
				<pubDate>Tue, 03 Feb 2026 13:00:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2026/02/revisiting-chatgpt-financial-advice</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2026/02/revisiting-chatgpt-financial-advice</guid>
			</item>
		
			<item>
				<title>Scaling Decision-Making: Guardrails Beat Gatekeepers</title>
				<description>&lt;p&gt;I walked into a budget meeting expecting the usual spreadsheet tour: what went up, what went down, and where we should trim next year. We did that. But in the middle of the call, something else surfaced: we were debating &lt;em&gt;how&lt;/em&gt; decisions should happen, not just &lt;em&gt;what&lt;/em&gt; the numbers were.&lt;/p&gt;

&lt;p&gt;Someone suggested a simple rule: any spend above a threshold should go to a committee for approval. It was well-intentioned, practical, and it looked good on paper.&lt;/p&gt;

&lt;p&gt;My first reaction was: &lt;em&gt;this won’t work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not because the threshold was too high or too low. But because the framing was off. It pushed strategy down to the operational level. It asked leaders across the company to act like mini-CFOs, to weigh trade-offs they don’t have context for. It created a system that depended on individual judgment instead of a repeatable path.&lt;/p&gt;

&lt;p&gt;That’s the opposite of systems thinking.&lt;/p&gt;

&lt;h2 id=&quot;systems-thinking&quot;&gt;Systems thinking&lt;/h2&gt;

&lt;p&gt;Systems thinking means you don’t fix outcomes &lt;strong&gt;only&lt;/strong&gt; by giving people more decisions, you fix outcomes by designing the system that shapes decisions. If you want different behavior, you redesign the structure: the incentives, the sequence, the guardrails.&lt;/p&gt;

&lt;p&gt;In practice, that means leadership has to do the hard part: define the path and remove ambiguity. The operation executes &lt;em&gt;within&lt;/em&gt; that path.&lt;/p&gt;

&lt;p&gt;So instead of telling everyone “spend less,” I prefer to ask: &lt;em&gt;what are the rails that will naturally lead to better spending?&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;enabling-constraints-the-rails&quot;&gt;Enabling constraints (the rails)&lt;/h2&gt;

&lt;p&gt;That’s where enabling constraints come in. They are rules and flows that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;limit the decision space,&lt;/li&gt;
  &lt;li&gt;make the right choice the default,&lt;/li&gt;
  &lt;li&gt;without killing autonomy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, the first draft of the policy was “anything above X needs approval.” The system-thinking version was different:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;First, internalize.&lt;/strong&gt; If a request is about an external vendor, the first step is always to route it through the internal capability. Only if that path is exhausted does the approval flow even start. The point isn’t “protecting internal teams.” It’s reducing avoidable spend and fragmentation &lt;strong&gt;when the capability already exists&lt;/strong&gt;, and escalating fast when it doesn’t.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Second, decide in the right moment.&lt;/strong&gt; The worst time to approve a vendor is when the proposal is already on the table and the deadline is tomorrow. The flow needs to exist &lt;em&gt;upstream&lt;/em&gt;, where the decision can be made calmly.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Third, separate strategy from execution.&lt;/strong&gt; Teams should focus on delivery and client outcomes. Leadership should define guardrails &lt;strong&gt;with the people who run the work&lt;/strong&gt; and monitor the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference is subtle but huge. Instead of asking people to make better decisions in chaotic situations, you reshape the process so the right decision is the easy one.&lt;/p&gt;

&lt;p&gt;None of this eliminates judgment. It just moves judgment to the &lt;em&gt;right layer&lt;/em&gt;: design the default path once, then let the organization run it repeatedly.&lt;/p&gt;

&lt;h2 id=&quot;what-i-proposed&quot;&gt;What I proposed&lt;/h2&gt;

&lt;p&gt;I proposed a lightweight “rail system” built around the reality of our operation:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Define the default path.&lt;/strong&gt; For certain categories (vendors, external analysis, specialized work), the default is &lt;em&gt;internal first&lt;/em&gt;. If it can’t be done internally, the request escalates.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Make the moment explicit.&lt;/strong&gt; Add checkpoints inside the workflow where the request must be raised early, not when it’s already late.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Keep approvals simple.&lt;/strong&gt; No ceremonies, no weekly meetings, no bureaucracy. Just clear inputs, fast review, and a decision trail. Clear inputs = scope, deadline, expected outcome, alternatives considered, and a rough cost envelope.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Define exception paths.&lt;/strong&gt; Legal/compliance requirements, incident response, hard external deadlines, or unique expertise not available internally. If an exception applies, the flow skips steps, but still leaves a decision trail.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In other words: leadership designs the system; the team follows the rails.&lt;/p&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h2&gt;

&lt;p&gt;This is not about being “tough on costs.” It’s about clarity. If you want a company to scale, you cannot rely on individual heroics or ad-hoc judgments. You need a system that consistently nudges people toward the strategic path.&lt;/p&gt;

&lt;p&gt;And building those systems is not easy. You need to identify what should change, understand why the current structure enables the old behavior, visualize alternatives, and think through side effects, incentives, and how to earn buy-in from the people involved. That’s real work.&lt;/p&gt;

&lt;p&gt;You know the rails are working when urgent approvals go down, repeat vendors consolidate, and lead time for “yes/no” decisions becomes predictable.&lt;/p&gt;

&lt;p&gt;The easy thing is to outsource the problem to leaders who are already constrained in their day-to-day. “Just approve everything” sounds simple, but it’s naive to think that passing the burden downstream will solve the root issue.&lt;/p&gt;

&lt;p&gt;Build the rails. Then let the train move fast.&lt;/p&gt;
</description>
				<pubDate>Tue, 23 Dec 2025 18:00:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2025/12/scaling-decisions-guardrails-beat-gatekeepers</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2025/12/scaling-decisions-guardrails-beat-gatekeepers</guid>
			</item>
		
			<item>
				<title>Anecdotal evidence of increased coding productivity with AI</title>
				<description>&lt;p&gt;I have been using AI to help me code (and actually to help me do anything) for a couple of years now. More and more I keep seeing how it boosts my productivity.&lt;/p&gt;

&lt;p&gt;When programming, I keep code suggestions minimal in the IDE and really like the chat interface for tackling coding tasks. Writing down the problem, its constraints, and the task goals in a structured way has, in my experience, shown really great results and visibly boosted my productivity. As a bonus, it has positively influenced the way I communicate about technical challenges with colleagues.&lt;/p&gt;

&lt;p&gt;So today, I saved some time to share a simple example — the anecdotal evidence. My task was to implement the following feature in a section of our app:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Automatically compress uploaded images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It took &lt;b&gt;25 minutes&lt;/b&gt; from start to finish. If I hadn’t used AI, I estimate that it would have taken me about &lt;b&gt;2 hours&lt;/b&gt; to search references, write down the code, test, and review before finishing this task.&lt;/p&gt;

&lt;p&gt;👉 That’s roughly a 5x speed-up in this particular case.&lt;/p&gt;

&lt;p&gt;Here’s a quick overview of how I structured my workflow using ChatGPT (GPT-4o model):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;b&gt;Define the Problem:&lt;/b&gt; I started by clearly defining my task, which was to compress uploaded images automatically in two user flows.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Generate Code:&lt;/b&gt; I asked ChatGPT to create a method for compressing images to high-quality JPEG, providing contextual code from my existing project.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Integrate Changes:&lt;/b&gt; Next, I requested ChatGPT to modify two existing image upload methods, incorporating the new compression method.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Create Unit Tests:&lt;/b&gt; Lastly, I asked ChatGPT to write a unit test for the new compression functionality following existing testing styles in the project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s take a deep dive.&lt;/p&gt;

&lt;h1 id=&quot;the-workflow-in-detail&quot;&gt;The Workflow in Detail&lt;/h1&gt;

&lt;p&gt;Initially, I reviewed the source code to understand the user flows I needed to change and to locate the image upload entry points.&lt;/p&gt;

&lt;p&gt;After getting familiar with the codebase, I concluded that the project didn’t yet define a method to compress images to JPEG. I also found an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ImageExtensions&lt;/code&gt; class that contained several methods for performing operations on images (e.g., Rotate, Resize, Generate thumbnail, etc.), which I decided was the right place to define the new compression method.&lt;/p&gt;

&lt;p&gt;So, in my first prompt to ChatGPT, I asked it to create the compression method, passing along additional contextual information to ensure the generated code would be compatible with my project:&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;prompt&lt;/span&gt;&lt;/p&gt;

  &lt;p&gt;In C# I’m using the following code for resizing images:&lt;/p&gt;

  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Drawing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Drawing.Drawing2D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Drawing.Imaging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Linq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Resize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newImage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Bitmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PropertyItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;newImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SetPropertyItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Graphics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SmoothingMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SmoothingMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AntiAlias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InterpolationMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;InterpolationMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HighQualityBicubic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PixelOffsetMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PixelOffsetMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HighQuality&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;graphics&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DrawImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newWidth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetImageFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RawFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;p&gt;Using the same referenced namespaces, how can I define a method for compressing images?&lt;/p&gt;

  &lt;p&gt;I want to compress PNG images into JPEG with high quality.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;In its response ChatGPT correctly produced the following method (I’m omitting additional information and the usage sample also returned by ChatGPT):&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;response&lt;/span&gt;&lt;/p&gt;

  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompressToJpeg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quality&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;90L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentNullException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Set JPEG quality encoder&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jpegEncoder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageCodecInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetImageDecoders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FirstOrDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FormatID&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Jpeg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jpegEncoder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;InvalidOperationException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;JPEG encoder not found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoderParams&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;EncoderParameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoderParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;EncoderParameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Quality&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quality&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MemoryStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jpegEncoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoderParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MemoryStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/div&gt;

&lt;p&gt;I skimmed through the code, and it seemed to implement everything I requested, so I copied and pasted the generated code into my project’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ImageExtensions&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;I continued by asking ChatGPT to adjust two of my application user flows to use the new method, with additional considerations:&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;prompt&lt;/span&gt;&lt;/p&gt;

  &lt;p&gt;Now consider these two methods which handle &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Image&lt;/code&gt; objects:&lt;/p&gt;

  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SaveCover&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coverName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coverStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateImageName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;covers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;coverName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SaveObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SaveIcon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iconStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateImageName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;icons&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iconStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SaveObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;ol&gt;
    &lt;li&gt;Check if the file name indicates that the image is PNG (or other uncompressed image file).&lt;/li&gt;
    &lt;li&gt;In case it is, call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompressToJpeg()&lt;/code&gt; and replace the name extensions to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jpeg&lt;/code&gt;.&lt;/li&gt;
  &lt;/ol&gt;

&lt;/div&gt;

&lt;p&gt;As a result, both methods were modified as requested, and ChatGPT proposed a helper method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsUncompressedImage&lt;/code&gt; to be used by both methods in accordance with the DRY (“don’t repeat yourself”) principle.&lt;/p&gt;

&lt;p&gt;Here’s the final code generated by ChatGPT for one of the methods after the introduced changes:&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;response&lt;/span&gt;&lt;/p&gt;

  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SaveIcon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iconStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isUncompressed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IsUncompressedImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isUncompressed&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ChangeExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.jpeg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iconName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GenerateImageName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;icons&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iconStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processedImage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isUncompressed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompressToJpeg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;90L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processedImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Jpeg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SaveObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/div&gt;

&lt;p&gt;Again, I reviewed the code and was happy with the proposed changes. After pasting it into my application code, everything compiled without any issues.&lt;/p&gt;

&lt;p&gt;Finally, before closing the code changes, I wanted to create a unit test for the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompressToJpeg&lt;/code&gt; method, so I sent another message to ChatGPT to create the test method analogous to another test in my project:&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;prompt&lt;/span&gt;&lt;/p&gt;

  &lt;p&gt;Now, create a unit test for the “CompressToJpeg” method. Follow the style below:&lt;/p&gt;

  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetGeolocatedImageCoordinateTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;Resources\geolocated.jpg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetCoordinate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsNotNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;22.8939933776855&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Latitude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;43.1236000061035&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Longitude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;p&gt;The test should:&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Load a @”Resources\Boots.png” image&lt;/li&gt;
    &lt;li&gt;Convert it to Jpeg&lt;/li&gt;
    &lt;li&gt;Assert that the compressed image size is less than 25% of the original image size&lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;Don’t save the compressed image to disk.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;And voilà, the unit test was correctly created according to my request:&lt;/p&gt;

&lt;div class=&quot;chat-message&quot;&gt;
  &lt;p&gt;&lt;span class=&quot;badge&quot;&gt;response&lt;/span&gt;&lt;/p&gt;

  &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompressToJpegTest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FromFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;Resources\Boots.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalStream&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MemoryStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compressedStream&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MemoryStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Save original image as PNG to stream&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;originalStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Png&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalSize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Compress to JPEG and save to stream&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compressed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompressToJpeg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;90L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compressed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compressedStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Jpeg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compressedSize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compressedStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Assert that the compressed image is less than 25% of the original size&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsTrue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compressedSize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalSize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;$&quot;Expected compressed size &amp;lt; 25% of original. Original: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;originalSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, Compressed: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compressedSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/div&gt;

&lt;p&gt;After pasting the new test method into my test class, I was able to quickly run it and confirm that it passed 🟢.&lt;/p&gt;

&lt;p&gt;Once I finished the code changes, I performed a manual test to validate that the task was completed:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img style=&quot;max-height: 240px; max-width: 100%; margin: 10px 0&quot; src=&quot;/images/p36/upload-request.png&quot; alt=&quot;Upload request in Chrome&apos;s network tab&quot; /&gt;
  &lt;br /&gt;&lt;label style=&quot;font-size: 12px;&quot;&gt;Figure 1. Upload request in Chrome&apos;s network tab&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;h1 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h1&gt;

&lt;p&gt;This was just one of many examples where AI tools can turbocharge the time it takes to complete manual code structuring and fiddly tasks. This task was a great candidate because it was mostly digital plumbing, relying on high-level operations (like JPEG compression) already provided by the underlying framework.&lt;/p&gt;

&lt;p&gt;Several studies try to capture how much productivity AI tools can bring. At the end of the day, it all depends on how frequently and how well you use them in your workflows.&lt;/p&gt;

&lt;p&gt;As with anything, usage brings experience, and we become better at identifying the best situations and strategies for extracting productivity from these tools. A naive approach of blindly using AI in everything may backfire.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;My complete conversation with ChatGPT can be accessed in the link below:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://chatgpt.com/share/67ed2912-af88-800b-835c-c0e0703a617f&quot;&gt;https://chatgpt.com/share/67ed2912-af88-800b-835c-c0e0703a617f&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Wed, 02 Apr 2025 13:55:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2025/04/anectodal-evidence-coding-productivity-with-ai</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2025/04/anectodal-evidence-coding-productivity-with-ai</guid>
			</item>
		
			<item>
				<title>Financial advice from ChatGPT? Let's give it a try!</title>
				<description>&lt;p&gt;I recently watched an interesting video titled &lt;a href=&quot;https://www.youtube.com/watch?v=ui7kRlJMqjM&quot;&gt;How AI &amp;amp; LLMs are Shaping Financial Advice&lt;/a&gt; by MIT Professor &lt;a href=&quot;https://mitsloan.mit.edu/faculty/directory/andrew-w-lo&quot;&gt;Andrew W. Lo&lt;/a&gt;. In it, he discusses how LLMs could be used for tasks like analyzing financial reports and offering sound financial advice. He also touches on the challenges of oversight, trust and fiduciary duty, sharing his thoughts on how these issues might be addressed in the long run.&lt;/p&gt;

&lt;p&gt;Right after that, YouTube suggested a news report from BBC about the Israel conflict in the Middle East, and that gave me an idea for an experiment. You see, we might be on the verge of an escalation in that conflict, and if it happens (I hope it doesn’t), I’m sure it’ll have a significant impact on the financial markets. I’m also sure that I’m not prepared for it, and that (again, if it happens) I’ll think in hindsight that I could have hedged against the real, though uncertain, possibility of escalation.&lt;/p&gt;

&lt;p&gt;So in this experiment, I prepared a simple CoT (Chain-of-Thought) prompt to enlighten me about the possibilities ahead and advise me on what I could do. Let’s take a look at it below.&lt;/p&gt;

&lt;h1 id=&quot;the-prompt&quot;&gt;The prompt&lt;/h1&gt;

&lt;div class=&quot;chat-message&quot;&gt;

  &lt;p&gt;If a conflict escalation occurs between Israel and Palestine in the Middle East, potentially involving Lebanon and possibly Iran…&lt;/p&gt;

  &lt;p&gt;1) What will happen to the global economy?&lt;/p&gt;

  &lt;p&gt;1.1) How might the global economy react if the conflict escalates further (e.g., involving the U.S.)?&lt;/p&gt;

  &lt;p&gt;2) Which currencies, commodities, bonds, and investments are likely to strengthen in this scenario, and which ones are likely to weaken?&lt;/p&gt;

  &lt;p&gt;3) How can I protect my capital in such a situation?&lt;/p&gt;

  &lt;p&gt;3.1) If the situation deescalates, what would be a balanced asset allocation strategy to hedge against both escalation and deescalation scenarios?&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;The purpose of this prompt is to first explain the typical impacts of conflict escalation on the global economy. Then, it analyzes the effects on an investor’s portfolio. Finally, it seeks advice on how to balance the portfolio, considering both the chances of escalation and de-escalation (essentially as a hedge).&lt;/p&gt;

&lt;p&gt;I think with a little more effort, we could’ve made an even better prompt. But it’s friday so let’s give this one a shot and see what we get!&lt;/p&gt;

&lt;h1 id=&quot;the-reply&quot;&gt;The reply&lt;/h1&gt;

&lt;div class=&quot;chat-message&quot;&gt;

  &lt;p&gt;If the conflict between Israel and Palestine escalates, especially involving countries like Lebanon, Iran, and potentially drawing in global powers like the U.S., the global economy could be affected in several ways. Here’s an overview of what could happen, which investments might be impacted, and how you could protect your capital:&lt;/p&gt;

  &lt;h3 id=&quot;global-economic-reaction-to-conflict-escalation&quot;&gt;1. Global Economic Reaction to Conflict Escalation&lt;/h3&gt;
  &lt;p&gt;If the conflict escalates into a broader regional war, the global economy could react in several ways:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Energy Supply Shocks:&lt;/strong&gt; The Middle East is a crucial hub for global oil production. Any conflict that disrupts production or threatens the Strait of Hormuz (through which a significant percentage of the world’s oil passes) could send oil prices soaring. This would lead to inflationary pressures globally, particularly in energy-dependent economies.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Market Volatility:&lt;/strong&gt; Investors might seek safer investments, leading to increased volatility in equity markets. Emerging markets could be especially vulnerable as they often rely on stable energy prices and foreign investment, both of which would be impacted.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Risk-Off Sentiment:&lt;/strong&gt; Global investors tend to shift to safer, low-risk assets in times of uncertainty or geopolitical turmoil, which can affect multiple asset classes.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

  &lt;hr /&gt;

  &lt;h3 id=&quot;impact-on-currencies-commodities-bonds-and-investments&quot;&gt;2. Impact on Currencies, Commodities, Bonds, and Investments&lt;/h3&gt;

  &lt;p&gt;&lt;strong&gt;Strengthening Assets:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Commodities (Oil and Gold):&lt;/strong&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;Oil:&lt;/strong&gt; Any conflict in the Middle East typically leads to a rise in oil prices due to potential supply disruptions. Energy stocks might see a boost as oil prices rise.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Gold:&lt;/strong&gt; Gold is traditionally viewed as a safe-haven asset during geopolitical tensions. Its price tends to rise when uncertainty or war escalates.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Currencies (USD and CHF):&lt;/strong&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;USD (U.S. Dollar):&lt;/strong&gt; The U.S. dollar tends to strengthen during global crises due to its status as a reserve currency and safe haven. Investors flock to the dollar in times of geopolitical instability.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;CHF (Swiss Franc):&lt;/strong&gt; Similar to the U.S. dollar, the Swiss franc is considered a stable, safe currency. It often appreciates during global turmoil.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Bonds (U.S. Treasuries, German Bunds):&lt;/strong&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;U.S. Treasuries:&lt;/strong&gt; Investors tend to move into U.S. Treasuries during times of global uncertainty. This will likely lead to lower yields (higher prices) for these bonds.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;German Bunds:&lt;/strong&gt; German bonds, considered some of the safest in Europe, are another place where investors might park capital during geopolitical crises.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Weakening Assets:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Equities (Especially in Emerging Markets):&lt;/strong&gt;
      &lt;ul&gt;
        &lt;li&gt;Stocks, particularly in riskier or emerging markets, are likely to decline as investor sentiment turns risk-averse. Even developed markets might face downturns as investors sell off riskier assets in favor of bonds or safer investments.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Middle Eastern Currencies (Israeli Shekel, Lebanese Pound):&lt;/strong&gt;
      &lt;ul&gt;
        &lt;li&gt;Currencies of countries directly involved in or geographically close to the conflict are likely to weaken. Investors may lose confidence in these currencies due to instability and fear of prolonged conflict.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

  &lt;hr /&gt;

  &lt;h3 id=&quot;protecting-your-capital-during-escalation&quot;&gt;3. Protecting Your Capital During Escalation&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Increase Allocation to Safe-Haven Assets:&lt;/strong&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;Gold and Precious Metals:&lt;/strong&gt; Allocate part of your portfolio to gold or other precious metals.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;U.S. Treasuries or Investment-Grade Bonds:&lt;/strong&gt; Move towards high-quality bonds, such as U.S. Treasuries, or investment-grade corporate bonds to reduce risk and provide stability during market volatility.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Hold More Cash in USD or CHF:&lt;/strong&gt; Having more liquidity in safe-haven currencies can provide flexibility and safety as the situation evolves.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Energy Sector Exposure:&lt;/strong&gt; Increasing exposure to energy stocks or commodities like oil could provide a hedge against rising energy prices during conflict escalation.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Diversification:&lt;/strong&gt; Ensure that your portfolio is diversified across geographies, sectors, and asset classes to minimize exposure to any one region or sector impacted by the conflict.&lt;/li&gt;
  &lt;/ul&gt;

  &lt;hr /&gt;

  &lt;h3 id=&quot;balanced-asset-allocation-strategy-for-escalation-and-de-escalation-scenarios&quot;&gt;4. Balanced Asset Allocation Strategy for Escalation and De-escalation Scenarios&lt;/h3&gt;

  &lt;p&gt;If you want to hedge against both escalation and de-escalation scenarios, you can adopt a balanced asset allocation strategy:&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Escalation Hedge:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Commodities Exposure:&lt;/strong&gt; Maintain some exposure to commodities like gold and oil. In times of escalation, these would benefit from flight-to-safety dynamics and potential supply disruptions.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Safe-Haven Bonds:&lt;/strong&gt; Allocate to U.S. Treasuries or other low-risk government bonds, as they would strengthen in the event of increased geopolitical risk.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;De-escalation Hedge:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Growth-Oriented Equities:&lt;/strong&gt; Once the situation deescalates, global equity markets may recover, particularly in sectors that are cyclically sensitive like technology, consumer discretionary, or industrials. Maintain some exposure to these equities to capture potential upside.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;&lt;strong&gt;Emerging Markets Exposure:&lt;/strong&gt; If tensions ease, emerging markets that were initially hit hard may rebound strongly, making them an attractive investment for growth in a de-escalated environment.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&lt;strong&gt;Overall Strategy:&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;60/40 or 50/30/20 Allocation:&lt;/strong&gt; A traditional balanced allocation could work:
      &lt;ul&gt;
        &lt;li&gt;&lt;strong&gt;60% Equities:&lt;/strong&gt; Diversify across geographies and sectors (some growth-oriented, some defensive).&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;40% Bonds:&lt;/strong&gt; Split between safe-haven government bonds and investment-grade corporate bonds.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;20% Commodities &amp;amp; Alternative Investments:&lt;/strong&gt; This portion can include gold, oil, and possibly some real estate or infrastructure investments that are less correlated with traditional assets.&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;By maintaining a diversified portfolio that includes both risk-on and risk-off assets, you can protect your capital and remain prepared for both escalation and de-escalation of geopolitical tensions.&lt;/p&gt;

&lt;/div&gt;

&lt;p&gt;There was a mix of stuff a bit obvious and some things that were new to me in the reply. But hey, sometimes the obvious needs to be said, right? Overall, I thought the info was pretty impressive. Then again, I’m not a financial analyst, so I might be falling into the &lt;a href=&quot;https://en.wiktionary.org/wiki/Gell-Mann_Amnesia_effect&quot;&gt;Gell-Mann Amnesia effect&lt;/a&gt; without even realizing it.&lt;/p&gt;

&lt;h1 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h1&gt;

&lt;p&gt;It was a fun, quick experiment, and I learned a thing or two about global dynamics. Even though I won’t be following this advice for practical reasons, the main goal was to share it openly and get feedback from some friends in the financial sector. I also want to let it sit for a while, maybe check back in a year to see if GPT-4’s advice was somewhat valuable or just generic/simplistic fluff.&lt;/p&gt;
</description>
				<pubDate>Fri, 04 Oct 2024 21:00:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2024/10/financial-advice-from-chatgpt</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2024/10/financial-advice-from-chatgpt</guid>
			</item>
		
			<item>
				<title>Easy-wins for generative AI</title>
				<description>&lt;p&gt;I will start this post with a direct question:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What are the most useful generative AI-powered product features you regularly use?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Think about it for a while. The answer usually includes [1]:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Chat apps (e.g., ChatGPT, Google Gemini)&lt;/li&gt;
  &lt;li&gt;Media generation tools (e.g., audio, image, video)&lt;/li&gt;
  &lt;li&gt;Code generation extensions (e.g., GitHub Copilot, Code Whisperer)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are indeed very useful! But weren’t we promised that generative AI would completely change every aspect of our lives? So why can’t most of us, specially non technical people, think of more examples to answer this question? The logical answer is that they aren’t that prevalent, yet.&lt;/p&gt;

&lt;p&gt;To add more context, it’s not that no one is trying. We’ve all seen prominent companies investing significant resources to ride the generative AI bandwagon. However, many of them decided to chase home runs instead of easy-wins, and for that reason a lot of them failed [2].&lt;/p&gt;

&lt;p&gt;So in this post, I’ll argue that to successfully adopt generative AI in your product, you should focus on easy wins rather than home runs.&lt;/p&gt;

&lt;h1 id=&quot;but-what-is-an-easy-win&quot;&gt;But what is an Easy-win?&lt;/h1&gt;

&lt;p&gt;An easy win, also known as a “low-hanging fruit,” can be defined as any product feature that delivers significant value to the end user while having relatively low implementation complexity:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img style=&quot;max-height: 240px; max-width: 100%; margin: 10px 0&quot; src=&quot;/images/p33/prioritization-matrix.PNG&quot; alt=&quot;Prioritization matrix&quot; /&gt;
  &lt;br /&gt;&lt;label style=&quot;font-size: 12px;&quot;&gt;Figure 1. Prioritization matrix&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;This concept originates from the prioritization matrix, a tool that helps teams manage tasks more efficiently, reduce viability risks, and optimize delivered value.&lt;/p&gt;

&lt;p&gt;It may seem obvious to target easy wins, but more often that not we get carried away chasing shiny objects and commit to poorly assessed challenges.&lt;/p&gt;

&lt;h1 id=&quot;how-to-discover-gen-ai-easy-wins&quot;&gt;How to discover gen AI easy-wins?&lt;/h1&gt;

&lt;p&gt;Considering that you may already have a working product that customers use (and love!), you should look for opportunities to improve your product’s &lt;b&gt;existing&lt;/b&gt; user flows to make them easier, faster, and more enjoyable.&lt;/p&gt;

&lt;p&gt;If we go back to the start of this post we can see that the gen AI apps that we use more often are those that save us time, make us more productive. Focus on that, make your customers more productive. That’s valuable.&lt;/p&gt;

&lt;p&gt;One way I like to think of generative AI, contrary to the belief that it’s a superintelligent being, is to consider it as &lt;b&gt;a very competent intern&lt;/b&gt; — one that can receive generic instructions and carry out low cognitive complexity tasks with reasonable precision. So, in the context of easy wins, avoid assigning your competent intern tasks that are too broad in scope, overly complex, or demand extreme precision. Those aren’t easy wins.&lt;/p&gt;

&lt;p&gt;Additionally, anticipate and prepare for imprecise results from generative AI. If you start with a zero-tolerance policy for errors, you’re likely to fail. Instead, design your solutions to support inexpensive review and regeneration cycles. This allows end users to easily assess the quality of the output and either accept it or quickly regenerate it if necessary.&lt;/p&gt;

&lt;p&gt;Wrapping It Up:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Target existing user flows&lt;/li&gt;
  &lt;li&gt;Search for opportunities to make your users more productive&lt;/li&gt;
  &lt;li&gt;Adopt gen AI for low-cognitive, narrowly scoped tasks&lt;/li&gt;
  &lt;li&gt;Design for inexpensive review and regeneration cycles&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;a-concrete-example&quot;&gt;A concrete example&lt;/h1&gt;

&lt;p&gt;I believe it’s important to provide a real world example to illustrate how these principles can be applied in practice. At &lt;a href=&quot;https://mindminers.com/en&quot;&gt;MindMiners&lt;/a&gt;, we offer innovative web and mobile market research solutions. Our customers create surveys on our platform and collect responses from our proprietary respondents panel via a mobile app.&lt;/p&gt;

&lt;p&gt;One of the most time-consuming user flows on our platform is the questionnaire creation process, so we decided to focus on improving it. A common low cognitive complexity task for survey creators is listing options for multiple-choice questions based on the question text. To streamline this, we added a button for generating options.&lt;/p&gt;

&lt;p&gt;Here’s how it looks - And of course, we took the opportunity to add some marketing flair to the icon and label there 😉:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img style=&quot;max-height: 320px; max-width: 100%; margin: 10px 0&quot; src=&quot;/images/p33/question-without-options.png&quot; alt=&quot;Question without options&quot; /&gt;
  &lt;br /&gt;&lt;label style=&quot;font-size: 12px;&quot;&gt;Figure 2. Question without options&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;Upon clicking this button, the platform constructs a simple prompt using the question text and requests a suggestion of options from the generative AI REST API. Once a result is generated, it is inserted into the frontend:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img style=&quot;max-height: 484px; max-width: 100%; margin: 10px 0&quot; src=&quot;/images/p33/question-with-options.png&quot; alt=&quot;Question with AI generated options&quot; /&gt;
  &lt;br /&gt;&lt;label style=&quot;font-size: 12px;&quot;&gt;Figure 3. Question with AI generated options&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;If the end user is not satisfied with the results, they can easily and quickly regenerate the question options and even provide additional instructions, such as specifying the number of options.&lt;/p&gt;

&lt;h1 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h1&gt;

&lt;p&gt;In this post, I outline a strategy for identifying opportunities to leverage your existing product with generative AI. Instead of pursuing overly ambitious and sophisticated features, I advocate for starting with simpler yet highly valuable improvements. I present a concrete example of a technically straightforward feature that we have developed and that was very well received by our users, demonstrating the effectiveness of this approach.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;[1] &lt;a href=&quot;https://news.ycombinator.com/item?id=39789250&quot;&gt;Ask HN: What are some of the best user experiences with AI?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2] &lt;a href=&quot;https://botharetrue.substack.com/p/every-app-that-adds-ai-looks-like&quot;&gt;Every app that adds AI looks like this&lt;/a&gt;&lt;/p&gt;

</description>
				<pubDate>Mon, 24 Jun 2024 19:30:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2024/06/easy-wins-for-generative-ai</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2024/06/easy-wins-for-generative-ai</guid>
			</item>
		
			<item>
				<title>Guidelines for addressing requests from colleagues</title>
				<description>&lt;p&gt;In the workplace we are constantly receiving requests from colleagues, and the more senior we get, the higher the demand for us. That’s natural and expected as we progress in our carrers and take on leadership roles.&lt;/p&gt;

&lt;p&gt;The way we address these requests has a direct impact on how we are perceived within the company and in the collaborative work environment we want to foster. I see them as opportunities to exercise communication and leadership skills, share knowledge, give feedback and positively impact my team and the business.&lt;/p&gt;

&lt;p&gt;Let’s take a look at how we can approach requests effectively, how seniority plays a role and analyze a few illustrative examples.&lt;/p&gt;

&lt;h1 id=&quot;guidelines&quot;&gt;Guidelines&lt;/h1&gt;

&lt;p&gt;In a nutshell, our communication in these situations should be driven by the following guidelines:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Employ empathy and nonviolent communication&lt;/li&gt;
  &lt;li&gt;Promote a cooperative, trusting, and supportive environment&lt;/li&gt;
  &lt;li&gt;Empower colleagues’ &lt;b&gt;autonomy&lt;/b&gt;&lt;/li&gt;
  &lt;li&gt;Advance colleagues’ technical skills&lt;/li&gt;
  &lt;li&gt;Focus on results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before responding to a request, reflect on whether your communication meets most of the above criteria, and whether it doesn’t directly go against any one of them. If your communication is aligned with this, proceed with confidence.&lt;/p&gt;

&lt;p&gt;Notice I deliberately highlighted ‘autonomy’, since I believe it plays a central role. In this context, it means that we should encourage our colleagues to seek solutions to their requests as autonomously as possible. It’s like the old saying: ‘Give a man a fish, and you feed him for a day; teach a man to fish, and you feed him for a lifetime’ (even though sometimes we’ll have no option other than give the fish - due to short deadlines, lack of experience of the courterpat, etc).&lt;/p&gt;

&lt;h1 id=&quot;seniority&quot;&gt;Seniority&lt;/h1&gt;

&lt;p&gt;Before heading to examples, a quick note on how the seniority level from our counterpart affects the way we communicate.&lt;/p&gt;

&lt;p&gt;Junior-level colleagues require more care and attention in communication, as they are in an early stage of professional development and need the consideration and support of more senior colleagues to help them grow. Positive and constructive feedback should be given frequently, and we should push them out of their comfort zone, but in a healthy and considerate way.&lt;/p&gt;

&lt;p&gt;In senior-to-senior relationships I encourage some friction. We need to have the courage to be honest with each other without beating around the bush, and trust in the maturity of our colleagues to receive feedback that is less polished, but constructive and insightful. This can speed things up and foster a more dynamic environment.&lt;/p&gt;

&lt;h1 id=&quot;examples&quot;&gt;Examples&lt;/h1&gt;

&lt;p&gt;To illustrate below are examples of typical reponses we often give. The first sentence in red shows an inadequate response according to the guidelines. The following sentence in green shows a more appropriate response. It is important to note that there isn’t only one way to act in each situation, and depending on your background and leadership style, your communication will vary. Additionally, keep in mind that we’re examining scenarios in which junior professionals seek assistance from their senior counterparts.&lt;/p&gt;

&lt;h2&gt;A)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: red&quot;&gt;“Hi Alice, I don&apos;t have time to help you, I&apos;m too busy.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a cold response, if you reply like this a lot then you’re not making yourself available to your colleagues, creating the perception that the door to collaboration is closed.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: green&quot;&gt;“Hi Alice, unfortunately I&apos;m very short on time today due to a priority activity I need to finish by the day&apos;s end. Is this urgent, or can we come back to this topic tomorrow? You can also check if Bill is available. Please keep me informed either way.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;This response shows adequate empathy, as it not only provides insight into your own situation but also expresses genuine interest in understanding the urgency behind the request. It further demonstrates cooperation by suggesting a schedule for assistance, possibly the next day. It also indicates alternative ways, such as exploring the availability of another colleague, possibly familiar with the subject, who could provide assistance.&lt;/p&gt;

&lt;h2&gt;B)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: red&quot;&gt;“Bob, you should be able to do this by yourself. Try harder”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;This can be characterized as a harsh response, especially for people at a more junior level, as, it potentially brings an unfavorable judgment of the person’s ability, and closes the door to collaboration.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: green&quot;&gt;“Bob, kindly share what you&apos;ve attempted so far, along with any unsuccessful attempts. This will help me grasp the context and offer more tailored guidance.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;This response aims to comprehend prior efforts through clear and well-crafted communication, naturally fostering the culture of autonomy valued within the company. It conveys the expectation that individuals have made an effort to address the issue independently before seeking assistance.&lt;/p&gt;

&lt;h2&gt;C)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: red&quot;&gt;“Hi Alice, look, I&apos;ve explained this to you several times, do some research.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, an example of a harsh response. Even though a subject may have been already discussed in the past, it’s essential to maintain an environment of trust and companionship by employing a more thoughtful communication.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: green&quot;&gt;“Hi Alice, I recall encountering this issue on multiple occasions in the past, and I believe that by revisiting our previous solutions, we can resolve it effectively. Please consider retrieving the approach we took when dealing with a similar situation, such as &apos;XYZ&apos;. If you have any questions, feel free to reach out. I&apos;m here to assist.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here, we assume an honest oversight without passing judgment, recognizing that we can sometimes struggle to recall past situations and apply them to new ones. With time and guidance, we can enhance this skill and progress. This presents a valuable opportunity to support a colleague’s technical development and foster their autonomy.&lt;/p&gt;

&lt;h2&gt;D)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: red&quot;&gt;“Bob, don&apos;t worry, I&apos;ll take a look and solve this problem by myself, I think it will be faster. I&apos;ll let you know when I&apos;m done.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first glance, this response appears cooperative and results-oriented. However, it contradicts the autonomy guideline by depriving the individual who sought help of the opportunity to learn and grow from the challenge. This approach can inadvertently foster dependency, as the person may not acquire the skills to handle similar situations independently in the future.&lt;/p&gt;

&lt;p&gt;Unless there’s a good reason to ‘hijack’ the problem, for instance due to a short deadline, the following approach is recommended:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style=&quot;color: green&quot;&gt;“Bob, this is a very interesting problem.  Let&apos;s discuss it, and I&apos;ll assist you in finding a solution. I anticipate it might arise in future scenarios, making it crucial to solidify this learning.”&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we see the clear mentoring approach, emphasizing the development of colleagues and a forward-looking perspective.&lt;/p&gt;

&lt;h1 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h1&gt;

&lt;p&gt;The more senior a team member becomes, the higher the expectation for them to have a positive impact on the team and subsequently in the business, inspiring and pushing their colleagues beyond their comfort zones, and thus earning recognition as a leader among peers.&lt;/p&gt;

&lt;p&gt;It’s far from easy; in fact, it’s quite challenging to assume the responsibilities of mentoring and take a prominent role within the team. Effective time management will be essential to strike a balance between safeguarding our personal time and remaining accessible to the team. This means prioritizing tasks, setting clear boundaries, and ensuring that our schedule allows for both focused work and availability to assist our colleagues. By efficiently managing our time, we can fulfill our leadership roles without becoming overwhelmed or unavailable when needed.&lt;/p&gt;

&lt;p&gt;The leadership challenge, whether in a managerial or technical role, is substantial, but the personal growth it brings is truly worth the effort.&lt;/p&gt;

</description>
				<pubDate>Mon, 16 Oct 2023 21:30:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2023/10/guideliness-for-requests-from-colleagues</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2023/10/guideliness-for-requests-from-colleagues</guid>
			</item>
		
			<item>
				<title>Setting up a reverse proxy using nginx and docker</title>
				<description>&lt;p&gt;A reverse proxy is a web server that sits between client devices and backend servers, receiving requests from clients and directing them to the appropriate server. The backend servers are shielded from direct internet access and their IP addresses are hidden, providing an additional layer of security.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img style=&quot;max-width: 100%; max-height: 240px; margin: 10px 0 10px -40px&quot; src=&quot;/images/p32/reverse-proxy.JPG&quot; alt=&quot;reverse-proxy&quot; /&gt;
  &lt;br /&gt;&lt;label style=&quot;font-size: 12px;&quot;&gt;Figure 1. A Reverse Proxy&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;Overall, reverse proxies are useful for improving security, performance, and scalability of web applications and services. They’re commonly used for load balacing traffic between any number of backend servers, and for SSL offloading.&lt;/p&gt;

&lt;p&gt;In this brief post I provide a template for setting up an nginx reverse proxy using docker.&lt;/p&gt;

&lt;h1 id=&quot;docker-compose&quot;&gt;Docker-compose&lt;/h1&gt;

&lt;p&gt;This is a docker-compose file with two services, the nginx web server that will act as a reverse proxy, and a certbot agent for enabling SSL connections to it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;version: &apos;3.3&apos;

services:

  nginx:
    image: nginx:1.19-alpine
    restart: always
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
    volumes:
      - ./volumes/nginx:/etc/nginx/conf.d
      - ./volumes/certbot/conf:/etc/letsencrypt
      - ./volumes/certbot/www:/var/www/certbot
    command: &quot;/bin/sh -c &apos;while :; do sleep 6h &amp;amp; wait $${!}; nginx -s reload; done &amp;amp; nginx -g \&quot;daemon off;\&quot;&apos;&quot;

  certbot:
    image: certbot/certbot
    restart: always
    volumes:
      - ./volumes/certbot/conf:/etc/letsencrypt
      - ./volumes/certbot/www:/var/www/certbot
    entrypoint: &quot;/bin/sh -c &apos;trap exit TERM; while :; do certbot renew; sleep 12h &amp;amp; wait $${!}; done;&apos;&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;b&gt;nginx&lt;/b&gt; service uses the official Nginx Docker image with version 1.19-alpine. It maps ports 80 and 443 to the host machine, which allows incoming HTTP and HTTPS requests to be forwarded to the Nginx container. The volumes section maps three directories on the host machine to directories in the container:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./volumes/nginx&lt;/code&gt; is mapped to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/conf.d&lt;/code&gt;, which allows custom Nginx configuration files to be added to the container.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./volumes/certbot/conf&lt;/code&gt; is mapped to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/letsencrypt&lt;/code&gt;, which stores the SSL/TLS certificates generated by Certbot.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./volumes/certbot/www&lt;/code&gt; is mapped to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/www/certbot&lt;/code&gt;, which is where Certbot writes temporary files during the certificate renewal process.&lt;/p&gt;

&lt;p&gt;The &lt;b&gt;certbot&lt;/b&gt; service uses the official Certbot Docker image. It also maps the same volumes as the nginx service. The entrypoint section specifies a shell command that is executed when the container starts up. This command runs a loop that sleeps for 12 hours before evaluating the renewal of SSL/TLS certificates using Certbot.&lt;/p&gt;

&lt;p&gt;Now let’s see how each service is configured.&lt;/p&gt;

&lt;h1 id=&quot;nginx&quot;&gt;Nginx&lt;/h1&gt;

&lt;p&gt;Below you’ll’ find an nginx configuration file that sets it up as a load balancer and reverse proxy for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thomasvilhena.com&lt;/code&gt; domain:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;### Nginx Load Balancer

upstream webapi {
	server 10.0.0.10;
	server 10.0.0.11;
	server 10.0.0.12; down;
}

server {
	listen 80;
	server_name localhost thomasvilhena.com;
	server_tokens off;
		
	location ^~ /.well-known/acme-challenge/ {
		default_type &quot;text/plain&quot;;
		alias /var/www/certbot/.well-known/acme-challenge/;
	}
		
	location = /.well-known/acme-challenge/ {
		return 404;
	}
		
	location / {
		return 301 https://thomasvilhena.com$request_uri;
	}
}


server {
	listen 443 ssl http2;
	server_name localhost thomasvilhena.com;
	server_tokens off;

	ssl_certificate /etc/letsencrypt/live/thomasvilhena.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/thomasvilhena.com/privkey.pem;
	include /etc/letsencrypt/options-ssl-nginx.conf;
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

	location / {
		proxy_pass http://webapi;
		proxy_set_header Host $http_host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-NginX-Proxy true;
		proxy_redirect off;
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The “upstream” section defines a group of servers to be load balanced, with three sample servers listed (10.0.0.10, 10.0.0.11, and 10.0.0.12). One server is marked as “down” which means it won’t receive requests.&lt;/p&gt;

&lt;p&gt;The first “server” block listens on port 80 and redirects all requests to the HTTPS version of the site. It also includes some configuration for serving temporary files over HTTP which are required for the SSL certificate renewal process through Let’s Encrypt.&lt;/p&gt;

&lt;p&gt;The second “server” block listens on port 443 for HTTPS traffic and proxies requests to the defined “upstream” group of servers. The “location /” block specifies that all URLs will be proxied. The various “proxy_set_header” directives are used to set the headers needed for the upstream servers to function correctly.&lt;/p&gt;

&lt;h1 id=&quot;certbot&quot;&gt;Certbot&lt;/h1&gt;

&lt;p&gt;Certbot requires two configuration files:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/volumes/certbot/conf/options-ssl-nginx.conf&lt;/code&gt; contains recommended security settings for SSL/TLS configurations in Nginx. Here’s a sample content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

ssl_ciphers &quot;ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/volumes/certbot/conf/ssl-dhparams.pem&lt;/code&gt; contains Diffie-Hellman parameters used for SSL/TLS connections. It is generated by running the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl dhparam -out /etc/letsencrypt/ssl-dhparams.pem 2048
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s a sample content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA3r1mOXp1FZPW+8kRJGBOBGGg/R87EBfBrrQ2BdyLj3r3OvXX1e+E
8ZdKahgB/z/dw0a+PmuIjqAZpXeEQK/OJdKP5x5G5I5bE11t0fbj2hLWTiJyKjYl
/2n2QvNslPjZ8TpKyEBl1gMDzN6jux1yVm8U9oMcT34T38uVfjKZoBCmV7g4OD4M
QlN2I7dxHqLShrYXfxlNfyMDZpwBpNzNwCTcetNtW+ZHtPMyoCkPLi15UBXeL1I8
v5x5m5DilKzJmOy8MPvKOkB2QIFdYlOFL6/d8fuVZKj+iFBNemO7Blp6WjKsl7Hg
T89Sg7Rln2j8uVfMNc3eM4d0SEzJ6uRGswIBAg==
-----END DH PARAMETERS-----
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;That’s it, now you just need to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose up&lt;/code&gt; and your reverse proxy should be up and running ✅&lt;/p&gt;
</description>
				<pubDate>Fri, 21 Apr 2023 15:30:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2023/04/setting-up-a-reverse-proxy</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2023/04/setting-up-a-reverse-proxy</guid>
			</item>
		
			<item>
				<title>The burden of complexity</title>
				<description>&lt;p&gt;Complexity is present in any project. Some have more, some have less, but it’s always there. The manner in which a team handles complexity can pave the way for a project’s success or lead towards its technical demise.&lt;/p&gt;

&lt;p&gt;In the context of software, complexity arises from a variety of factors, such as complicated requirements, technical dependencies, large codebases, integration challenges, architectural decisions, team dynamics, among others.&lt;/p&gt;

&lt;p&gt;When talking to non-technical folks, especially those not acquainted with the concepts of software complexity and technical debt, it can be helpful to present the topic from a more managerial perspective.&lt;/p&gt;

&lt;p&gt;So I propose the following qualitative diagram that regards complexity as an inherent property of a software project, and simultaneously, a responsibility that a software development team must constantly watch and manage for being able to deliver value in the long run:&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img style=&quot;max-width: 100%; max-height: 400px; margin: 10px 0 10px -40px&quot; src=&quot;/images/p31/complexity-burden-diagram.png&quot; alt=&quot;surface&quot; /&gt;
  &lt;br /&gt;&lt;label style=&quot;font-size: 12px;&quot;&gt;Figure 1. The Complexity Burden Diagram&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;From the diagram:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;b style=&quot;color:blue&quot;&gt;Complexity Burden&lt;/b&gt; curve represents the theoretical amount of effort necessarily spent servicing complexity, as oposed to productive work. This is an inevitable aspect of software development and can manifest in various forms, including spending time understanding and working with complex code, encountering more intricate bugs and errors, updating depencencies, struggling to onboard new team members due to excessively elaborate designs, among others.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;b style=&quot;color:gray&quot;&gt;Team’s Capacity&lt;/b&gt; line is the maximum amount of effort the team is able to provide, which varies over time and can be influenced by factors such as changes in the product development process, team size, and efforts to eliminate toil [1]. Additionally, reductions in the complexity burden of a project can unlock productivity, influencing the team’s capacity as well.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;b style=&quot;color:gray&quot;&gt;Complexity Threshold&lt;/b&gt; represents the point where the team’s capacity becomes equal to the complexity burden. In this theoretical situation, the team is only allocating capacity towards servicing complexity. Value delivery is compromised.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these definitions in place, let’s review the two colored zones depicted in the diagram.&lt;/p&gt;

&lt;h2&gt;The Improvment Zone&lt;/h2&gt;

&lt;p&gt;Projects are typically in the improvement zone, which means that &lt;u&gt;the team has enough capacity to handle the complexity burden and still perform productive work&lt;/u&gt;. The lower the complexity burden, the more efficient and productive the team will be in delivering results. The team can choose to innovate, develop new features, optimize performance, and improve UX. It’s worth noting that doing so may result in added complexity. This is acceptable as long as there is sufficient capacity to deal with the added complexity in the next cycles of development and the team remains continuously committed to addressing technical debt.&lt;/p&gt;

&lt;h2&gt;The Degradation Zone&lt;/h2&gt;

&lt;p&gt;A project enters the degradation zone when &lt;u&gt;the team&apos;s capacity is insufficient for adequately servicing complexity&lt;/u&gt;, adding pressure on an already strangled project. The team will constantly be putting out fires, new features will take longer to ship, bugs will be more likely to be introduced, developers may suggest rewriting the application, availability may be impaired, and customers may not be satisfied. The viable ways out of this situation are to significantly reduce complexity or to increase capacity. Other efforts will be mostly fruitless.&lt;/p&gt;

&lt;h1 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;/h1&gt;

&lt;p&gt;The concept of complexity burden can be a valuable tool for enriching discussions around promoting long-term value delivery and preventing a project from becoming bogged down by complexity, leaving little room for new feature development. It’s important to make decisions with a clear understanding of the complexity burden and how it may be affected.&lt;/p&gt;

&lt;p&gt;It’s worth pointing out that if the productive capacity of a team is narrow, meaning if the proportion of the team’s capacity allocated towards the complexity burden is already too high, the team will find itself in a situation where continuing to innovate may be too risky. The wise decision then will be to prioritize paying off technical debt and investing in tasks to alleviate the complexity burden.&lt;/p&gt;

&lt;p&gt;Even though they are related, it’s crucial to distinguish between the complexity burden and technical debt. The former materializes as the amount of (mostly) non-productive work a team is encumbered by, while the latter is a liability that arises from design or implementation choices that prioritize short-term gains over long-term sustainability [2]. A project can become highly complex even with low technical debt.&lt;/p&gt;

&lt;p&gt;Finally, a project is a dynamic endeavor, and a team may find itself momentarily in the “degradation” zone in one cycle and in the “improvement” zone in the next. What matters most is to be aware of the technical context and plan next steps preemptively, aiming to maintain the complexity burden at a healty level.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;[1] &lt;a href=&quot;https://sre.google/sre-book/eliminating-toil/&quot;&gt;Google - Site Reliability Engineering. Chapter 5 - Eliminating Toil&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2] &lt;a href=&quot;https://en.wikipedia.org/wiki/Technical_debt&quot;&gt;Wikipedia - Technical debt&lt;/a&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 10 Apr 2023 16:30:00 +0000</pubDate>
				<link>https://thomasvilhena.com/2023/04/the-burden-of-complexity</link>
				<guid isPermaLink="true">https://thomasvilhena.com/2023/04/the-burden-of-complexity</guid>
			</item>
		
	</channel>
</rss>
