<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Lunatech's engineer blog</title>
	<atom:link href="https://blog.lunatech.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.lunatech.com</link>
	<description>Simplify your IT</description>
	<lastBuildDate>Sun, 24 Jan 2021 09:46:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	weekly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>Lunatech's blog engine</generator>

<image>
	<url>https://blog.lunatech.com/assets/images/logo-lunatech-france.png</url>
	<title>Lunatech's engineer blog</title>
	<link>https://blog.lunatech.com</link>
	<width>32</width>
	<height>32</height>
</image> 

 
	<item>
		<title>AI Is Collapsing the Cost of Software. Here Are the Numbers.</title>
		<link>https://blog.lunatech.com//posts/2026-05-12-ai-is-collapsing-the-cost-of-software</link>
		
		<dc:creator><![CDATA[Nicolas Leroux]]></dc:creator>
        <pubDate>2026-05-12T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[AI]]></category>
                }
             {
            <category><![CDATA[software cost]]></category>
                }
             {
            <category><![CDATA[agentic coding]]></category>
                }
             {
            <category><![CDATA[productivity]]></category>
                }
             {
            <category><![CDATA[legacy modernization]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2026-05-12-ai-is-collapsing-the-cost-of-software</guid>

					<description>
                        <![CDATA[ Every previous industrial revolution replaced muscle. Steam engines, assembly lines, tractors -- each one amplified physical labor and made goods cheaper to produce. The revolution happening right now is different in kind. For the first time, what is being replaced is the ability to produce structured intellectual output: code, documentation, test plans, architecture decisions, migration scripts, compliance reports.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Every previous industrial revolution replaced muscle. Steam engines, assembly lines, tractors&#8201;&#8212;&#8201;each one amplified physical labor and made goods cheaper to produce. The revolution happening right now is different in kind. For the first time, what is being replaced is the ability to produce structured intellectual output: code, documentation, test plans, architecture decisions, migration scripts, compliance reports.</p>
</div>
<div class="paragraph">
<p>This is not a future scenario. It is already measurable, benchmarked, and accelerating.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_timeline_of_ai_assisted_development">The timeline of AI-assisted development</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The shift has happened in barely five years. In 2020, AI in software development meant autocomplete&#8201;&#8212;&#8201;Copilot-style code suggestions that saved a few keystrokes. By 2022, ChatGPT had replaced Stack Overflow as the first place developers looked for answers. In 2024, AI became embedded in CI/CD pipelines: generating tests, reviewing pull requests, checking architecture consistency. And in 2026, we have entered the era of agentic coding&#8201;&#8212;&#8201;AI agents that plan, implement, and verify multi-step tasks autonomously.</p>
</div>
<div class="paragraph">
<p>Each of these stages represents not just a feature improvement but a qualitative shift in what AI can do. We have gone from "help me write a function" to "here is the specification, the constraints, and the context&#8201;&#8212;&#8201;build the module, write the tests, and verify the output."</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_numbers_do_not_lie">The numbers do not lie</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The benchmarks are clear and consistent across multiple independent studies.</p>
</div>
<div class="paragraph">
<p>46% of code written by GitHub Copilot users is now AI-generated. A study across 4,000 developers showed a 26% productivity boost. Controlled experiments report 55% faster task completion.</p>
</div>
<div class="paragraph">
<p>And these are already outdated figures. GPT-4 in 2023 was good at snippets. Claude 3.5 in 2024 could handle full-file rewrites. Claude Code in 2025 introduced agentic workflows&#8201;&#8212;&#8201;multi-step tasks with self-correction. Claude Opus 4 brought multi-step planning, self-verification, and parallel agent execution.</p>
</div>
<div class="paragraph">
<p>Every six months, a generation leap. The curve is not flattening&#8201;&#8212;&#8201;it is steepening.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2026-05-12-ai-is-collapsing-the-cost-of-software/cost-collapse.png" alt="Costs">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_becomes_economically_viable">What becomes economically viable</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The real impact is not that developers type less. It is that entire categories of projects that were previously too expensive suddenly become affordable.</p>
</div>
<div class="paragraph">
<p>Legacy systems that were too expensive to replace? Now within reach. Custom software that was reserved for large budgets? Accessible to smaller companies. Complete test suites that nobody had time to write? Generated automatically.</p>
</div>
<div class="paragraph">
<p>Consider the concrete numbers:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Project</th>
<th class="tableblock halign-left valign-top">2020 (Traditional)</th>
<th class="tableblock halign-left valign-top">2026 (AI-Accelerated)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">COBOL Migration (1M lines)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">$9.1M, 18 months</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">$2-4M, 6-8 months</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Custom CRM Development</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">$500K, 12 months</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">$80K, 3 months</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Full Test Suite (legacy app)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">$200K, 6 months</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">$15K, 2 weeks</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Same scope. Same quality. Fraction of the cost.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_this_matters_for_legacy_modernization">Why this matters for legacy modernization</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For decades, the standard answer to "should we modernize?" has been a cost-benefit analysis where the costs were terrifyingly high and the benefits were uncertain. That calculus has fundamentally changed.</p>
</div>
<div class="paragraph">
<p>The average cost of modernization&#8201;&#8212;&#8201;$9.1 million per Deloitte&#8201;&#8212;&#8201;was the perfect excuse to do nothing. But when AI can reverse-engineer business rules from a COBOL codebase in two weeks instead of three months, when it can translate modules with verified behavioral equivalence, when it can generate test suites from golden datasets automatically, the cost curve collapses.</p>
</div>
<div class="paragraph">
<p>This does not mean modernization becomes trivial. It means it becomes feasible. The economic barrier that protected legacy systems from replacement has eroded. What remains is the organizational will to act.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_inaction_tax_is_now_unbearable">The inaction tax is now unbearable</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When action cost millions and took years, inaction could be rationalized. The system works. The risk is too high. We will revisit next quarter.</p>
</div>
<div class="paragraph">
<p>But when action costs a fraction of what it did, and the alternative is continuing to pay $200K per year just to keep the lights on, the calculation flips. The "inaction tax"&#8201;&#8212;&#8201;the cumulative cost of maintaining, patching, and working around a legacy system&#8201;&#8212;&#8201;now exceeds the cost of replacing it.</p>
</div>
<div class="paragraph">
<p>When action costs almost nothing, inaction becomes inexcusable.</p>
</div>
<div class="paragraph">
<p>In the next article, we will explore what this means for the people who build software. If AI is producing the code, what is the new role of the engineer?</p>
</div>
<hr>
<div class="paragraph">
<p><em>This is the third in a series of five articles based on the talk "Software Will Cost Almost Nothing. What Happens Next?" Read the full series on our blog.</em></p>
</div>
<div class="paragraph">
<p><em>Sources: GitHub Copilot Impact Study (2025), McKinsey Digital Productivity Report (2024), Google DeepMind (2024), Deloitte Legacy Modernization Cost Analysis (2025), Lunatech client data.</em></p>
</div>
<div class="paragraph">
<p><em>Contact: <a href="mailto:nicolas.leroux@lunatech.com">nicolas.leroux@lunatech.com</a> | <a href="https://lunatech.com">lunatech.com</a></em></p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>The Cost of Inaction: Why Standing Still Is the Most Expensive Decision in Tech</title>
		<link>https://blog.lunatech.com//posts/2026-05-05-the-cost-of-inaction</link>
		
		<dc:creator><![CDATA[Nicolas Leroux]]></dc:creator>
        <pubDate>2026-05-07T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[cost of inaction]]></category>
                }
             {
            <category><![CDATA[legacy modernization]]></category>
                }
             {
            <category><![CDATA[tech debt]]></category>
                }
             {
            <category><![CDATA[digital transformation]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2026-05-05-the-cost-of-inaction</guid>

					<description>
                        <![CDATA[ In 1977, Ken Olsen, the founder of Digital Equipment Corporation, declared: "There is no reason anyone would want a computer in their home." DEC was worth $14 billion at the time. It no longer exists.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In 1977, Ken Olsen, the founder of Digital Equipment Corporation, declared: "There is no reason anyone would want a computer in their home." DEC was worth $14 billion at the time. It no longer exists.</p>
</div>
<div class="paragraph">
<p>This is not a story about prediction failures. It is a story about what happens when organizations see disruption coming and choose to stand still. And if you are running a legacy system in 2026, this story is about you.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_famous_last_words">Famous last words</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The pattern is always the same. A dominant player sees the future but decides that the present is comfortable enough. Kodak invented the digital camera in 1975&#8201;&#8212;&#8201;thirty-seven years before filing for bankruptcy. Blockbuster declined a partnership with Netflix in 2000 for $50 million; Netflix is now worth over $250 billion. BlackBerry dismissed the iPhone as a toy in 2007 and watched its market share fall to zero.</p>
</div>
<div class="paragraph">
<p>None of these companies lacked engineers, resources, or market intelligence. What they lacked was the willingness to cannibalize their own success in order to survive. They chose the comfort of the status quo over the discomfort of transformation.</p>
</div>
<div class="paragraph">
<p>And the status quo killed them.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_meanwhile_in_2026">Meanwhile, in 2026</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The numbers tell a sobering story. There are still 240 billion lines of COBOL in production worldwide. 43% of banking and insurance systems run on mainframes designed in the 1960s. The average cost to modernize a legacy system has historically been around $9.1 million&#8201;&#8212;&#8201;a figure that has served as the perfect excuse to postpone.</p>
</div>
<div class="paragraph">
<p>Every year, companies spend billions maintaining systems that were obsolete a decade ago: patching vulnerabilities in frameworks that are no longer supported, onboarding developers into codebases that nobody fully understands, and running parallel infrastructure because the old system "still works" even though it cannot integrate with modern tools.</p>
</div>
<div class="paragraph">
<p>"We&#8217;ll modernize next year," says every CTO since 2015. Spoiler: next year never comes. And the bill keeps growing.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_three_hidden_costs">The three hidden costs</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The cost of inaction is rarely visible on a balance sheet. It manifests in three dimensions.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2026-05-05-the-cost-of-inaction/three-costs.png" alt="The three hidden costs">
</div>
</div>
<div class="paragraph">
<p>The first is <strong>technical</strong>. Every year of postponement adds another layer of tech debt. Interfaces become more brittle, dependencies more tangled, and the pool of developers who understand the system shrinks. The longer you wait, the harder and more expensive the migration becomes. This is not linear&#8201;&#8212;&#8201;it is exponential.</p>
</div>
<div class="paragraph">
<p>The second is <strong>organizational</strong>. Companies that do not modernize tend to develop rigid, flat structures where no one owns the decision to change. Committees form. Reports are commissioned. Proof-of-concept projects are launched and quietly shelved. The organizational muscle for transformation atrophies.</p>
</div>
<div class="paragraph">
<p>The third is <strong>personal</strong>. For the software engineers working on these systems, inaction means stale skill sets. Still building Struts MVC applications in 2026? Because of inertia? A stale skill set does not land new jobs, and it does not keep old ones interesting. Being a good engineer is not about knowing a particular technology. It is about understanding the business and learning fast.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_europes_particular_challenge">Europe&#8217;s particular challenge</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There is a cultural dimension to this as well. Europe favors stability, consensus, and regulation. The US moves fast, encourages risk-taking, and rewards bold innovation. The result? Europe has missed leadership in cloud, AI, social media, and platform economics.</p>
</div>
<div class="paragraph">
<p>This is not because European engineers are less talented. It is because the institutional incentive in Europe is to avoid failure rather than pursue success. And fear of failure leads directly to missed opportunity. Innovation requires courage, not just competence.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_inaction_is_a_choice">Inaction is a choice</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The instinct to delay is understandable. Modernization is complex, expensive, and risky. But the cost of not modernizing is also complex, expensive, and risky&#8201;&#8212;&#8201;it is just less visible.</p>
</div>
<div class="paragraph">
<p>Every day a legacy system stays in production is a day of compounding cost: maintenance overhead, security exposure, opportunity cost of features that cannot be built, and the slow erosion of competitive position.</p>
</div>
<div class="paragraph">
<p>Inaction does not protect you. It just delays the consequences.</p>
</div>
<div class="paragraph">
<p>The good news? The economics of modernization have changed dramatically. In the next article, we will explore how AI is collapsing the cost of building software&#8201;&#8212;&#8201;and why projects that were unthinkable two years ago are now within reach.</p>
</div>
<hr>
<div class="paragraph">
<p><em>This is the second in a series of five articles based on the talk "Software Will Cost Almost Nothing. What Happens Next?" Read the full series on our blog.</em></p>
</div>
<div class="paragraph">
<p><em>Contact: <a href="mailto:nicolas.leroux@lunatech.com">nicolas.leroux@lunatech.com</a> | <a href="https://lunatech.com">lunatech.com</a></em></p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Software Will Cost Almost Nothing. What Happens Next?</title>
		<link>https://blog.lunatech.com//posts/2026-04-28-software-will-cost-almost-nothing</link>
		
		<dc:creator><![CDATA[Nicolas Leroux]]></dc:creator>
        <pubDate>2026-04-28T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[AI]]></category>
                }
             {
            <category><![CDATA[software engineering]]></category>
                }
             {
            <category><![CDATA[legacy modernization]]></category>
                }
             {
            <category><![CDATA[agentic coding]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2026-04-28-software-will-cost-almost-nothing</guid>

					<description>
                        <![CDATA[ Every industrial revolution until now replaced muscle. The steam engine, the assembly line, the tractor -- each one amplified physical labor and made goods cheaper to produce. But the revolution we are living through right now is fundamentally different. For the first time, what is being replaced is the ability to produce structured intellectual output: code, documentation, test plans, architecture decisions, migration scripts, compliance reports. All of these can now be produced by AI agents.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Every industrial revolution until now replaced muscle. The steam engine, the assembly line, the tractor&#8201;&#8212;&#8201;each one amplified physical labor and made goods cheaper to produce. But the revolution we are living through right now is fundamentally different. For the first time, what is being replaced is the ability to produce structured intellectual output: code, documentation, test plans, architecture decisions, migration scripts, compliance reports. All of these can now be produced by AI agents.</p>
</div>
<div class="paragraph">
<p>The implications for our industry are staggering. If software&#8201;&#8212;&#8201;the most valuable and most expensive asset of the modern enterprise&#8201;&#8212;&#8201;can be produced at a fraction of today&#8217;s cost, then what changes?</p>
</div>
<div class="paragraph">
<p>Everything.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_cost_of_inaction_is_no_longer_abstract">The cost of inaction is no longer abstract</h2>
<div class="sectionbody">
<div class="paragraph">
<p>At RivieraDev 2025, my co-speaker Quentin Adam and I delivered a keynote titled "The Cost of Inaction." The thesis was simple: standing still is the most expensive decision a company can make.</p>
</div>
<div class="paragraph">
<p>The evidence was everywhere. Kodak invented the digital camera in 1975 and filed for bankruptcy in 2012. Blockbuster declined a partnership with Netflix in 2000 and closed 9,000 stores. BlackBerry dismissed the iPhone in 2007 and holds zero market share today. None of these companies lacked talent or technology. They lacked the courage to act.</p>
</div>
<div class="paragraph">
<p>Meanwhile, in 2026, 240 billion lines of COBOL remain in production. 43% of banking and insurance systems still run on mainframes. The average cost to modernize? $9.1 million&#8201;&#8212;&#8201;until now.</p>
</div>
<div class="paragraph">
<p>The hidden costs of inaction are technical (accumulated tech debt, lost innovation capacity), organizational (flat structures that lack ownership), and personal (stalled careers, missed opportunities). Inaction does not protect you. It just delays the consequences.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_but_what_if_the_cost_of_action_collapses">But what if the cost of action collapses?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This is where the story takes a dramatic turn. AI-assisted software development has moved from autocomplete in 2020 to fully agentic coding in 2026. The numbers are unambiguous: 46% of code written by Copilot users is AI-generated, productivity gains of 26% across thousands of developers, and 55% faster task completion in controlled experiments. And these benchmarks are already months old&#8201;&#8212;&#8201;every quarter brings another generation leap.</p>
</div>
<div class="paragraph">
<p>Consider what this means in practical terms. A COBOL migration that cost $9.1 million and took 18 months in 2020 can now be completed for $2-4 million in 6-8 months. A custom CRM that required $500K and a year of development can be built for $80K in three months. A full test suite for a legacy application that would have cost $200K and six months of manual work can be generated for $15K in two weeks.</p>
</div>
<div class="paragraph">
<p>Same scope. Same quality. Fraction of the cost.</p>
</div>
<div class="paragraph">
<p>When action costs almost nothing, inaction becomes inexcusable.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_engineers_become_orchestrators">Engineers become orchestrators</h2>
<div class="sectionbody">
<div class="paragraph">
<p>But there is a catch. AI does not mean pressing a button and watching the magic happen. Without structure, AI produces plausible but generic output that needs extensive rework. The difference between success and failure lies entirely in methodology.</p>
</div>
<div class="paragraph">
<p>The new role of the software engineer is not to type code. It is to orchestrate AI agents&#8201;&#8212;&#8201;curating context, defining quality gates, structuring work, verifying output, and accumulating knowledge over time. Like a conductor in front of an orchestra, the engineer sets the tempo, the dynamics, and the interpretation. The performance depends entirely on the score.</p>
</div>
<div class="paragraph">
<p>This is captured in a simple equation:</p>
</div>
<div class="paragraph lead">
<p><strong>AI Output Quality = AI Capability x Context Quality</strong></p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2026-04-28-software-will-cost-almost-nothing/equation.png" alt="The AI Equation: Output Quality = AI Capability × Context Quality">
</div>
</div>
<div class="paragraph">
<p>AI capability improves every quarter. You cannot control it. Context quality is the lever you own. This is where engineering discipline makes the difference between a demo and production-grade software.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_a_battle_tested_methodology">A battle-tested methodology</h2>
<div class="sectionbody">
<div class="paragraph">
<p>At Lunatech, we have spent the past year building a methodology that makes AI-accelerated modernization reliable, reproducible, and predictable. Our Legacy Modernization with AI framework is built on seven phases&#8201;&#8212;&#8201;Discover, Reverse-Engineer, Re-Architect, Rebuild, Migrate, Harden, Handover&#8201;&#8212;&#8201;each with clear deliverables and exit gates.</p>
</div>
<div class="paragraph">
<p>At the heart of the framework is the Claude (or Copilot) Context Pack: a versioned, curated knowledge base with seven layers (System, Code, Data, Business, Architecture, Test, Decision) that feeds every AI task with precisely the right context. A dedicated AI engineer builds, curates, and maintains it throughout the engagement.</p>
</div>
<div class="paragraph">
<p>The result? Small teams of 2-4 senior engineers plus a dedicated AI engineer consistently outperform larger traditional teams. Parity is verified through behavioral equivalence testing and parallel running&#8201;&#8212;&#8201;not assumed. And the context pack is transferred to the client as a durable asset at handover: the living documentation the legacy system never had.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_this_means_for_you">What this means for you</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you are a CTO sitting on a legacy system and thinking "we&#8217;ll modernize next year," know that next year never comes. And the bill keeps growing. If you are a software engineer still building the same kind of applications with the same kind of tools, your skill set is becoming stale. The competitive advantage is shifting from code production to speed and judgment.</p>
</div>
<div class="paragraph">
<p>The cost of software is collapsing. The skill is no longer writing code&#8201;&#8212;&#8201;it is orchestrating agents. And methodology is what separates production-grade output from demos.</p>
</div>
<div class="paragraph">
<p>Take the first step. Start something.</p>
</div>
<hr>
<div class="paragraph">
<p><em>This is the first in a series of five articles based on my talk "Software Will Cost Almost Nothing. What Happens Next?" For more details on each theme, follow the series on our blog and on LinkedIn.</em></p>
</div>
<div class="paragraph">
<p><em>Contact: <a href="mailto:nicolas.leroux@lunatech.com">nicolas.leroux@lunatech.com</a> | <a href="https://lunatech.com">lunatech.com</a></em></p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Devoxx France 2026</title>
		<link>https://blog.lunatech.com//posts/2026-04-24-devoxx-france-2026</link>
		
		<dc:creator><![CDATA[Antoine Bastos]]></dc:creator>
        <pubDate>2026-04-24T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[devoxx-fr]]></category>
                }
             {
            <category><![CDATA[ai]]></category>
                }
             {
            <category><![CDATA[java]]></category>
                }
             {
            <category><![CDATA[conference]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2026-04-24-devoxx-france-2026</guid>

					<description>
                        <![CDATA[ I spent two days at https://www.devoxx.fr/[Devoxx France 2026] at the Palais des Congrès in Paris. The buzz words of this edition were hard to miss: AI, Vibe Coding, Claude, Agentic, Context, Determinism. Out of sixteen talks I attended, more than half dealt with AI in some form. The conference carried genuine optimism : barriers are falling, tools are powerful, now is the time to experiment. But the talks that stuck with me most went further. ]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>I spent two days at <a href="https://www.devoxx.fr/">Devoxx France 2026</a> at the Palais des Congrès in Paris. The buzz words of this edition were hard to miss: AI, Vibe Coding, Claude, Agentic, Context, Determinism. Out of sixteen talks I attended, more than half dealt with AI in some form. The conference carried genuine optimism : barriers are falling, tools are powerful, now is the time to experiment. But the talks that stuck with me most went further.
They examined where AI breaks, what it costs, and what discipline it demands. Here is what I took away.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_ai_will_solve_everything_right">AI Will Solve Everything&#8230;&#8203; Right?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Devoxx opened with keynotes spanning from enthusiasm to existential warning.</p>
</div>
<div class="sect2">
<h3 id="_prompt_ship_test">Prompt, Ship, Test</h3>
<div class="paragraph">
<p>Nicolas Grenié set the tone on day one. The barriers to building are collapsing. Solo developers ship prototypes that would have taken teams months. Product Managers pick up Figma and Claude and start dreaming. His message: experiment now, ship, test. Both the tools and the way we use them will keep changing. Do not wait.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_right_to_be_lazy">The Right to Be Lazy</h3>
<div class="paragraph">
<p>Jean-Gabriel Ganascia, a philosopher and engineer, delivered his entire keynote without a single slide, a rare move at Devoxx. He opened with Paul Lafargue&#8217;s 19th-century manifesto <em>The Right to Be Lazy</em>: if machines handle the drudgery, humans should work three hours a day and spend the rest thinking.</p>
</div>
<div class="paragraph">
<p>Generative AI seems to fulfill that promise. It reads thousands of pages of reports, produces them, makes decisions. We keep only the rewarding tasks. "From that perspective, it&#8217;s wonderful," Ganascia said.</p>
</div>
<div class="paragraph">
<p>Then he flipped the argument and laid out four risks:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Boredom.</strong> If we delegate cognitive work, will we have enough to keep our minds occupied? He quoted Baudelaire&#8217;s <em>Fleurs du mal</em>, "It is Boredom!", as a warning.</p>
</li>
<li>
<p><strong>The capitalist hydra won&#8217;t wither away.</strong> "Be honest — do you really believe that? Not long ago Meta laid off 8,000 people." AI will make large companies more profitable, not free workers.</p>
</li>
<li>
<p><strong>De-skilling.</strong> If we stop learning to read, write, and code on our own, what remains?</p>
</li>
<li>
<p><strong>Moral alignment as censorship.</strong> Who decides what an AI may or may not say? Ganascia mentioned France Travail&#8217;s plan for AI-assisted annual interviews, a project that raises questions about large-scale behavioral control.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>His closing warning: after the Bronze Age, the Iron Age, and the Information Age, we risk entering the Age of Falsification and Control.</p>
</div>
</div>
<div class="sect2">
<h3 id="_vibe_coding_meets_reality">Vibe Coding Meets Reality</h3>
<div class="paragraph">
<p>Marjory Canonne, who advises SMEs on AI adoption, described the gap between expectations and outcomes. Many companies approach AI in FOMO mode, hoping for immediate ROI. When she explains what AI actually is and what it costs, many lose interest.</p>
</div>
<div class="paragraph">
<p>Her advice to companies: start by systematizing internal knowledge. Mine your data, capitalize on experience, speed up information access across the organization. That delivers value. Jumping straight to customer-facing AI products does not. During Q&amp;A, a developer asked: what do you do when a Product Manager vibe-codes a prototype, then says "we can cut your budget, one dev will clean this up"? She responded that some companies will have to learn that the hard way. Grenié added with humour: "Where we used to have 500 days to deliver, we&#8217;ll now have 5 days of vibe-coded prototype and 495 days cleaning up the mess."</p>
</div>
<div class="paragraph">
<p>My own concern here: there is no certainty about the future of LLMs. Today AI is cheap. Providers sell at a loss. Putting an AI-as-a-service (GPT, Claude, Gemini) at the core of a product&#8217;s business domain means accepting uncertainty by design: non-deterministic behavior, provider version changes, price hikes, or disappearance.</p>
</div>
</div>
<div class="sect2">
<h3 id="_datacenters_and_the_sovereignty_paradox">Datacenters and the Sovereignty Paradox</h3>
<div class="paragraph">
<p>Loup Cellard, an anthropology researcher at Sciences Po, shifted the conversation to physical infrastructure. His talk mapped how submarine cables shape datacenter deployments in France. Marseille (7th best-connected city in the world) and Bordeaux (where Meta&#8217;s "Amitié" cable arrives) concentrate the installations. The result: conflicts over energy between public transit and datacenters, land speculation, and a sovereignty paradox. Local authorities told Cellard they do not understand the government&#8217;s position: France talks about digital sovereignty while welcoming US players, sometimes on publicly funded infrastructure.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_engineering_with_ai_agents_discipline_over_hype">Engineering with AI Agents: Discipline Over Hype</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If the keynotes asked "should we?", the afternoon talks asked "how do we do it properly?"</p>
</div>
<div class="sect2">
<h3 id="_four_patterns_for_agentic_ai">Four Patterns for Agentic AI</h3>
<div class="paragraph">
<p>Guillaume Laforge presented four design patterns for AI agents, each addressing the same core problem: LLMs degrade when you give them too much at once.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Progressive Disclosure.</strong> Organize agent capabilities into skills, each with an abstract header and a detailed body. A <code>SKILL.md</code> index lets the agent load only what it needs. (See <a href="https://github.com/glaforge/deslopify">Deslopify skills</a> on GitHub.)</p>
</li>
<li>
<p><strong>Hierarchical Decomposition.</strong> Break work into sequential steps with specialized agents. One writes an article, another de-slops it. The tradeoff is more latency and sometimes more tokens.</p>
</li>
<li>
<p><strong>LLM-as-Judge.</strong> Use one model to evaluate another&#8217;s output. Three summaries from Gemini 2.5 Flash Lite plus one review from Gemini 2.5 Flash costs roughly $0.80, versus $2.00 for a single Gemini 3.1 Pro summary, and produces better results.</p>
</li>
<li>
<p><strong>GOAP (Goal-Oriented Action Planning).</strong> A supervisor LLM receives a high-level objective and orchestrates specialized agents. Laforge demonstrated this with LangChain4j.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_constrain_the_puzzle">Constrain the Puzzle</h3>
<div class="paragraph">
<p>Cyrille Martraire and Olivier Penhoat presented a legacy migration case study where they used AI to generate end-to-end API tests.</p>
</div>
<div class="paragraph">
<p>Their first approach was to have the AI run the tests by querying both APIs and comparing responses. It worked 100% of the time, but was slow, expensive, and non-deterministic. JSON payloads of ~400 KB ate the context window, and results varied between runs.</p>
</div>
<div class="paragraph">
<p>Their second approach worked: the AI generates the tests instead of running them. They constrained the problem with two files: a <code>.yml</code> describing test scenarios and a <code>pivot-format.spec.md</code> specifying how to map old API responses to new ones. The AI fills in only the test implementation. Expensive once (generation), nearly free afterwards (standard execution). The principle: <strong>constrain the AI to fill one piece of the puzzle, not generate the whole puzzle.</strong> The more precise the framework you provide, the more deterministic the output.</p>
</div>
</div>
<div class="sect2">
<h3 id="_context_engineering_for_deterministic_ai">Context Engineering for Deterministic AI</h3>
<div class="paragraph">
<p>Benoît Fontaine&#8217;s talk on taming AI agents reinforced the same idea from the tooling side. His key points:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Performance degrades not because of context size, but because of what is in the context. Compact at 60%, never exceed 80%. If auto-compaction kicks in, the session is dead.</p>
</li>
<li>
<p>Maintain at least two files: <code>AGENTS.md</code> (cross-tool source of truth with architecture rules, conventions, workflows, strict rules) and <code>CLAUDE.md</code> (tool-specific adapter). Keep each under 200 lines.</p>
</li>
<li>
<p>Place scoped context files in relevant directories (<code>/frontend</code>, <code>/backend</code>).</p>
</li>
<li>
<p>Ideal session workflow: research, compact, plan, compact, implement.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>His closing line resonated: "AI is an amplifier of the current state. If the documentation and specs were already clean, the AI output will be clean." In other words, operational maturity matters more than which model you pick.</p>
</div>
<div class="paragraph">
<p>Presentation repo: <a href="https://github.com/b-fontaine/devoxx-2026" class="bare">https://github.com/b-fontaine/devoxx-2026</a></p>
</div>
</div>
<div class="sect2">
<h3 id="_claude_code_in_30_minutes">Claude Code in 30 Minutes</h3>
<div class="paragraph">
<p>Erwan Gereec delivered 30 Claude Code tips in 30 minutes. A few stood out:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>/init</code> analyzes the codebase and initializes <code>CLAUDE.md</code>, a natural starting point for context engineering.</p>
</li>
<li>
<p><code>/compact keep the developed API and remove explorations</code> targets compaction instead of blind compression.</p>
</li>
<li>
<p><code>/insights</code> generates a detailed HTML report analyzing your usage habits, with personalized tips.</p>
</li>
<li>
<p>Custom skills live in <code>.claude/skills/&lt;name&gt;/SKILL.md</code> for repeatable workflows.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_java_keeps_shipping">Java Keeps Shipping</h2>
<div class="sectionbody">
<div class="paragraph">
<p>AI dominated, but Java had its own strong showing.</p>
</div>
<div class="sect2">
<h3 id="_value_types_codes_like_a_class_works_like_an_int">Value Types: Codes Like a Class, Works Like an Int</h3>
<div class="paragraph">
<p>If you hadn&#8217;t already followed java incoming evolutions, Rémi Forax and Clément de Tastes presented <a href="https://openjdk.org/jeps/401">Project Valhalla</a>, the largest refactoring in JDK history (2,665 files modified, +200k lines). The core idea : using a new <code>value</code> keyword before <code>class</code> or <code>record</code> gives up the object&#8217;s identity in exchange for memory flattening and scalarization.</p>
</div>
<div class="paragraph">
<p>Using a <a href="https://github.com/rokon12/Mandelbrot">Mandelbrot</a> visualisation tool, they showed that switching from <code>record</code> to <code>value record</code> reduced GC pressure by 143x and memory usage by 88%. The JIT compiler can scalarize value types, copying field values directly into CPU registers because the objects are immutable and identity-free.</p>
</div>
<div class="paragraph">
<p>Beyond raw performance, this will inevitably change the way we code by using more immutable objects and data structures. We must be aware now that current JDK <code>@ValueBased</code> annotated classes will automatically become value classes (no recompilation needed for old libraries).
Furthermore, a new <code>!</code> (bang) operator will guarantee non-nullity for array flattening, and <code>==</code> comparison will be possible on value objects (in that case, this is not a reference comparison, but a value comparison). But there are traps though : <code>==</code> on a value class holding a <code>String</code> field compares the reference, not the content. Moreover, <code>synchronized</code> won&#8217;t work because the lock relies on the object header, which won&#8217;t exist on value classes.</p>
</div>
</div>
<div class="sect2">
<h3 id="_structured_concurrency">Structured Concurrency</h3>
<div class="paragraph">
<p>José Paumard ran a 3-hour hands-on lab on the Structured Concurrency API (Project Loom), available in JDK 27 early access. Virtual threads (JDK 21) made threads cheap to create, but Java still lacked a concurrency model to match. Running parallel tasks meant either chaining <code>CompletableFuture</code> callbacks or adopting a reactive framework — both sacrifice readability and stack traces. Structured Concurrency fills that gap: fork tasks on virtual threads, write sequential-looking code, and let the scope handle cancellation and error propagation automatically.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">try (var scope = StructuredTaskScope.open(Joiner.allSuccessfulOrThrow())) {
    scope.fork(taskA);
    scope.fork(taskB);
    scope.join();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Multiple <code>Joiner</code> strategies handle success, failure, and timeouts. Structured Concurrency isn’t new as an idea. What Project Loom brings is making it finally practical at scale thanks to virtual threads, because platform threads are expensive to create and do not scale well when used in large numbers.</p>
</div>
<div class="paragraph">
<p>Lab repo: <a href="http://github.com/JosePaumard/2026_DevoxxFR-Loom-lab" class="bare">http://github.com/JosePaumard/2026_DevoxxFR-Loom-lab</a></p>
</div>
</div>
<div class="sect2">
<h3 id="_in_brief">In Brief</h3>
<div class="ulist">
<ul>
<li>
<p><strong>Victor Rentea</strong> delivered the funniest talk of the conference on Event-Driven Architecture pitfalls, covering ordering, partition keys, phantom writes, and idempotency. It moved too fast to capture in notes. Worth rewatching on <a href="https://youtube.com/@devoxxfrvideos?si=fo6T_UhA31Q1lx31">YouTube</a>.</p>
</li>
<li>
<p><strong>Thomas Pierrain and Julien Topçu</strong> presented "The Hive." Starting from a Big Ball of Mud, they showed how to modularize a monolith through vertical slicing, then isolate each module as a hexagon with adapters that translate types between modules so domain models never leak from one hexagon to another. Once that structure is in place, extracting a module into a microservice becomes straightforward.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Build up AI skills now. The tools are powerful and priced below cost; that window will close. But tooling alone won&#8217;t save you, as clean documentation and clear specs make AI output better, while sloppy inputs produce sloppy outputs, faster.
AI needs a clear framework to fill in the missing pieces; constraining the puzzle is the key to tackle its lack of determinism.
And Java keeps evolving. Value types, structured concurrency, and virtual threads address real performance and concurrency pain points. Valhalla alone justifies paying attention to the next JDK releases.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Change Detection Strategies in Angular: Zones and Signals</title>
		<link>https://blog.lunatech.com//posts/2025-11-05-change-detection-strategies-in-angular-zones-and-signals</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-11-05T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[Intermediate]]></category>
                }
             {
            <category><![CDATA[change detection]]></category>
                }
             {
            <category><![CDATA[Zone.js]]></category>
                }
             {
            <category><![CDATA[OnPush]]></category>
                }
             {
            <category><![CDATA[signals (intro)]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-11-05-change-detection-strategies-in-angular-zones-and-signals</guid>

					<description>
                        <![CDATA[ Understand Angular’s change detection mechanism and how to optimize performance using the OnPush strategy. Learn how to use Signals for more granular reactivity. This article provides a practical mental model and shows how to apply it with Zone.js, OnPush, and Signals, along with a clear path toward building zoneless applications when you’re ready.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Understand Angular’s change detection mechanism and how to optimize performance using the OnPush strategy. Learn how to use Signals for more granular reactivity. This article provides a practical mental model and shows how to apply it with Zone.js, OnPush, and Signals, along with a clear path toward building zoneless applications when you’re ready.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_the_mental_model_how_angular_knows_to_update">The mental model: how Angular knows to update</h3>
<div class="paragraph">
<p>At a high level, Angular renders your component tree into a graph of views. A change detection pass checks template bindings and updates the DOM where something changed. Something has to tell Angular when to do that pass:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>With Zone.js (the default), Angular patches async APIs (Promises, setTimeout, DOM events, etc.) and schedules checks automatically after those tasks.</p>
</li>
<li>
<p>With signals, writes to a signal schedule the right components to re-render even without Zone.js.</p>
</li>
<li>
<p>With OnPush, Angular narrows when a component is checked: on input reference changes, events in that component, async pipe emissions, and signal writes.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Once you see what triggers checks, you can guide Angular to do less work and update only when it matters.</p>
</div>
</div>
<div class="sect2">
<h3 id="_working_with_zone_js_default">Working with Zone.js (default)</h3>
<div class="paragraph">
<p>Zone.js intercepts most async boundaries and calls into Angular to run change detection. It’s a safe default and reduces boilerplate, especially for teams migrating legacy code.</p>
</div>
<div class="paragraph">
<p>You can configure Zone.js coalescing to reduce redundant checks:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// app.config.ts
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    // Collapses multiple events/microtasks into fewer change detection cycles.
    provideZoneChangeDetection({
      eventCoalescing: true,
      runCoalescing: true,
    }),
    provideHttpClient(),
  ],
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>For performance-sensitive work (e.g., animations or polling), run it outside Angular to avoid thrashing, and re-enter only when UI state actually changes.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import {
  Component,
  NgZone,
  ChangeDetectionStrategy,
  signal,
  inject,
  OnInit,
  OnDestroy
} from '@angular/core';

@Component({
  selector: 'cpu-heavy',
  standalone: true,
  template: `
    &lt;p&gt;Frames: {{ frames() }}&lt;/p&gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CpuHeavyComponent implements OnInit, OnDestroy {
  private zone = inject(NgZone);

  // Signal handles reactivity; no CDR needed
  private _frames = signal(0);
  frames = this._frames.asReadonly();

  private intervalId?: ReturnType&lt;typeof setInterval&gt;;

  ngOnInit() {
    this.zone.runOutsideAngular(() =&gt; {
      let n = 0;
      this.intervalId = setInterval(() =&gt; {
        // Update signal outside Angular zone
        // Signals batch updates automatically
        this._frames.set(++n);

        if (n &gt; 3000) {
          clearInterval(this.intervalId);
        }
      }, 16);
    });
  }

  ngOnDestroy() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
  }
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_embracing_onpush_for_predictable_performance">Embracing OnPush for predictable performance</h3>
<div class="paragraph">
<p>OnPush reduces unnecessary checks and nudges you toward immutable data and explicit updates. Angular will check an OnPush component when:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>An Input reference changes (immutability shines here).</p>
</li>
<li>
<p>The component fires an event or an async pipe emits.</p>
</li>
<li>
<p>A bound signal writes (signals integrate with the scheduler).</p>
</li>
<li>
<p>You explicitly call markForCheck or detectChanges.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Use immutable updates for inputs and track nodes for stable lists.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, ChangeDetectionStrategy, input } from '@angular/core';

type User = { id: number; name: string };

@Component({
  selector: 'user-list',
  standalone: true,
  template: `
    &lt;ul&gt;
      @for (u of users(); track u.id) {
        &lt;li&gt;{{ u.name }}&lt;/li&gt;
      }
    &lt;/ul&gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UserListComponent {
  // Signal-based input (works great with OnPush)
  users = input&lt;ReadonlyArray&lt;User&gt;&gt;([]);
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// parent.component.ts
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { UserListComponent } from './user-list.component';

type User = { id: number; name: string };

@Component({
  selector: 'parent',
  standalone: true,
  imports: [UserListComponent],
  template: `
    &lt;button (click)="add()"&gt;Add&lt;/button&gt;
    &lt;button (click)="mutate()"&gt;Mutate (bad)&lt;/button&gt;

    &lt;user-list [users]="users()"&gt;&lt;/user-list&gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ParentComponent {
  private _users = signal&lt;ReadonlyArray&lt;User&gt;&gt;([
    { id: 1, name: 'Maya' },
    { id: 2, name: 'Dee' },
  ]);
  users = this._users.asReadonly();

  // Correct: immutable update changes the reference and triggers OnPush
  add() {
    const currentIds = this.users().map(u =&gt; u.id);
    const nextId = currentIds.length &gt; 0 ? Math.max(...currentIds) + 1 : 1;
    this._users.update(arr =&gt; [...arr, { id: nextId, name: 'New User' }]);
  }

  // Bad: mutates in place; OnPush children won't see a different reference
  mutate() {
    // as any to showcase the pitfall (avoid in real code)
    (this.users() as any)[0].name = 'Mutated';
    // The UI may not update; prefer immutable patterns.
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you&#8217;re not using signals and you must update UI from a callback that Angular doesn&#8217;t know about, call markForCheck.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit } from '@angular/core';

@Component({
  selector: 'ws-status',
  standalone: true,
  template: `Status: {{ status }}`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WebSocketStatusComponent implements OnInit {
  status = 'disconnected';
  constructor(private cdr: ChangeDetectorRef) {}

  ngOnInit() {
    const ws = new WebSocket('wss://example.org');
    ws.onopen = () =&gt; { this.status = 'connected'; this.cdr.markForCheck(); };
    ws.onclose = () =&gt; { this.status = 'disconnected'; this.cdr.markForCheck(); };
  }
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';

@Component({
  selector: 'ws-status',
  standalone: true,
  template: `Status: {{ status }}`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WebSocketStatusComponent {
  status = 'disconnected';
  constructor(private cdr: ChangeDetectorRef) {}

  ngOnInit() {
    const ws = new WebSocket('wss://example.org');
    ws.onopen = () =&gt; { this.status = 'connected'; this.cdr.markForCheck(); };
    ws.onclose = () =&gt; { this.status = 'disconnected'; this.cdr.markForCheck(); };
  }
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_signals_intro_finegrained_reactivity_without_heavy_lifting">Signals (intro): fine‑grained reactivity without heavy lifting</h3>
<div class="paragraph">
<p>Signals give you a declarative, dependency-tracked model for state. Reading a signal in a template links it to the view; writing to that signal schedules the right view to update. This makes change detection more targeted and pairs naturally with OnPush or even zoneless.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, ChangeDetectionStrategy, signal, computed, effect } from '@angular/core';

type Todo = { id: number; title: string; done: boolean };

@Component({
  selector: 'todo-panel',
  standalone: true,
  template: `
    &lt;input placeholder="Filter..." [value]="filter()" (input)="filter.set(($event.target as HTMLInputElement).value)" /&gt;

    &lt;p&gt;Completed: {{ completedCount() }} / {{ todos().length }}&lt;/p&gt;

    &lt;ul&gt;
      @for (t of filteredTodos(); track t.id) {
        &lt;li&gt;
          &lt;label&gt;
            &lt;input type="checkbox" [checked]="t.done" (change)="toggle(t.id)" /&gt;
            {{ t.title }}
          &lt;/label&gt;
        &lt;/li&gt;
      }
    &lt;/ul&gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TodoPanelComponent {
  private _todos = signal&lt;Todo[]&gt;([
    { id: 1, title: 'Ship dashboard', done: false },
    { id: 2, title: 'Write docs', done: true },
  ]);
  todos = this._todos.asReadonly();

  filter = signal('');
  filteredTodos = computed(() =&gt; {
    const q = this.filter().toLowerCase();
    return this.todos().filter(t =&gt; t.title.toLowerCase().includes(q));
  });
  completedCount = computed(() =&gt; this.todos().filter(t =&gt; t.done).length);

  toggle(id: number) {
    this._todos.update(ts =&gt; ts.map(t =&gt; (t.id === id ? { ...t, done: !t.done } : t)));
  }

  // Optional: side effects
  log = effect(() =&gt; {
    console.debug('Todos changed:', this.todos());
  });
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Interop with RxJS is straightforward; toSignal turns an Observable into a signal that drives OnPush views.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { toSignal } from '@angular/core/rxjs-interop';
import { Observable } from 'rxjs';

@Component({ /* ... */ })
export class ClockComponent {
  now = toSignal(
    // Emits a new Date every second
    new Observable&lt;Date&gt;(sub =&gt; {
      const id = setInterval(() =&gt; sub.next(new Date()), 1000);
      return () =&gt; clearInterval(id);
    }),
    { initialValue: new Date() }
  );
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Because writing to signals schedules view updates, you often don’t need ChangeDetectorRef calls. The result is simpler, more predictable change detection.</p>
</div>
</div>
<div class="sect2">
<h3 id="_zoneless_change_detection_when_youre_ready_to_drop_zone_js">Zoneless change detection: when you&#8217;re ready to drop Zone.js</h3>
<div class="paragraph">
<p>Zoneless mode lets Angular skip patching browser APIs (no Zone.js) and rely purely on explicit reactive triggers (signals, template events, async pipe, router). By Angular 20, zoneless is mature enough for production in well-structured, signal‑driven apps.</p>
</div>
<div class="paragraph">
<p>Use the stable provider if it exists; otherwise keep using the experimental one until your project confirms the upgrade path.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// app.config.ts
import { ApplicationConfig, provideHttpClient } from '@angular/common/http';
import {
  // Verify which one exists in your installed version:
  // If Angular 20 exposes `provideZonelessChangeDetection`, prefer it.
  provideZonelessChangeDetection,               // &lt;-- Confirm availability
  provideExperimentalZonelessChangeDetection,   // &lt;-- Fallback if stable not present
} from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    // Use ONE of the following:
    // provideZonelessChangeDetection(),
    provideExperimentalZonelessChangeDetection(), // ← Remove when stable provider confirmed
    provideHttpClient(),
  ],
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>With zoneless, Angular still updates views when:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Template events fire (click, input, etc.).</p>
</li>
<li>
<p>A signal is written (set/update).</p>
</li>
<li>
<p>AsyncPipe emits (it marks its view manually).</p>
</li>
<li>
<p>Router navigation completes.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Other async sources (WebSocket, timers, SDK callbacks): funnel them through signals (or Observables bound via async pipe / toSignal). Avoid manual ChangeDetectorRef unless integrating with legacy patterns.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { interval, map, startWith } from 'rxjs';

@Component({
  selector: 'zoneless-demo',
  standalone: true,
  template: `
    &lt;p&gt;Server time: {{ time() }}&lt;/p&gt;
    &lt;p&gt;Clicks: {{ clicks() }}&lt;/p&gt;
    &lt;button (click)="inc()"&gt;Click me&lt;/button&gt;
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZonelessDemoComponent {
  time = toSignal(
    interval(1000).pipe(
      map(() =&gt; new Date().toLocaleTimeString()),
      startWith(new Date().toLocaleTimeString()),
    ),
    { initialValue: new Date().toLocaleTimeString() },
  );

  private _clicks = signal(0);
  clicks = this._clicks.asReadonly();

  inc() {
    this._clicks.update(n =&gt; n + 1);
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you interact with non-Angular callbacks (e.g., third‑party SDKs), prefer to set signals inside the callback. That write will schedule the needed view updates.</p>
</div>
</div>
<div class="sect2">
<h3 id="_practical_checklist">Practical checklist</h3>
<div class="ulist">
<ul>
<li>
<p>Prefer OnPush for all app components; combine with immutable data.</p>
</li>
<li>
<p>Use signal-based inputs (input()) in leaf components for ergonomic, fine-grained updates.</p>
</li>
<li>
<p>Store local UI state as signals; use computed for derivations and effect for side effects.</p>
</li>
<li>
<p>In Zone.js apps, isolate heavy loops with runOutsideAngular and re-enter only on state writes.</p>
</li>
<li>
<p>In zoneless apps, ensure all UI-affecting async work flows through signals or async pipe.</p>
</li>
<li>
<p>Track list items by a stable key to avoid re-render churn.</p>
</li>
<li>
<p>Use provideZoneChangeDetection with coalescing in legacy/mixed environments; move toward provideExperimentalZonelessChangeDetection when your reactive pathways are solid.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_troubleshooting_gotchas">Troubleshooting gotchas</h3>
<div class="ulist">
<ul>
<li>
<p>“My OnPush child didn’t update.” Ensure the Input reference changes (immutable update) or the child reads a signal that you wrote to.</p>
</li>
<li>
<p>“Zoneless didn’t repaint after a callback.” Convert that callback’s data to a signal or trigger an async pipe emission; avoid manual detectChanges unless you know the implications.</p>
</li>
<li>
<p>“Perf regressions after refactor.” Check for unintended synchronous effects that write many signals in a loop; batch updates if needed, or compose a single state write.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_conclusion">Conclusion</h3>
<div class="paragraph">
<p>Change detection in Angular is powerful because you can choose the right tool for the job. Zone.js gives you simplicity, OnPush gives you predictability and performance, and signals give you precise, maintainable reactivity. Together, they help you ship fast UIs without guesswork, and you can progressively adopt a zoneless model when your state is signal-driven.</p>
</div>
</div>
<div class="sect2">
<h3 id="_next_steps">Next Steps</h3>
<div class="ulist">
<ul>
<li>
<p>Audit your components: enable OnPush and fix any mutable input flows.</p>
</li>
<li>
<p>Introduce signals for local state and derived values; replace ad‑hoc ChangeDetectorRef calls.</p>
</li>
<li>
<p>Wrap recurring async sources (timers, sockets) with toSignal or async pipe.</p>
</li>
<li>
<p>Experiment with provideExperimentalZonelessChangeDetection in a feature slice to validate your reactive pathways.</p>
</li>
<li>
<p>Read the Angular guides on signals and zoneless change detection to deepen your understanding.</p>
</li>
</ul>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Getting Started with Angular 20 CLI and Standalone Components</title>
		<link>https://blog.lunatech.com//posts/2025-10-27-getting-started-with-angular-20-cli-and-standalone-components</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-10-27T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[Beginner]]></category>
                }
             {
            <category><![CDATA[Angular CLI]]></category>
                }
             {
            <category><![CDATA[standalone components]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-10-27-getting-started-with-angular-20-cli-and-standalone-components</guid>

					<description>
                        <![CDATA[ Learn how to initialize and structure a new Angular 20 project using the Angular CLI. Understand standalone components and the simplified bootstrapping process. This guide focuses on a clean project setup, modern routing, and practical patterns you can reuse in real projects.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Learn how to initialize and structure a new Angular 20 project using the Angular CLI. Understand standalone components and the simplified bootstrapping process. This guide focuses on a clean project setup, modern routing, and practical patterns you can reuse in real projects.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_prerequisites">Prerequisites</h3>
<div class="ulist">
<ul>
<li>
<p>Node.js 24+ (LTS recommended) and npm or pnpm</p>
</li>
<li>
<p>Angular CLI 20 installed globally: npm i -g @angular/cli@20</p>
</li>
<li>
<p>Familiarity with TypeScript and Angular fundamentals</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_create_a_new_project_with_the_angular_cli">Create a new project with the Angular CLI</h3>
<div class="paragraph">
<p>The Angular CLI scaffolds a production-grade baseline with sensible defaults. Standalone components are the default in Angular 20, which means no NgModules are required for most apps.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell" data-lang="shell">// Terminal
// Create a new app with routing and SCSS. Use --ssr to scaffold server-side rendering.
ng new lt-dashboard --routing --style=scss
cd lt-dashboard
ng serve</code></pre>
</div>
</div>
<div class="paragraph">
<p>Open <a href="http://localhost:4200" class="bare">http://localhost:4200</a> and confirm the app runs. The CLI gives you fast dev server reloads, TypeScript checks, and a ready-to-extend project.</p>
</div>
</div>
<div class="sect2">
<h3 id="_project_structure_that_scales">Project structure that scales</h3>
<div class="paragraph">
<p>A small, predictable layout keeps cognitive load low as features grow.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// Suggested structure (simplified)
src/
  main.ts
  index.html
  styles.scss
  environments/
    environment.ts
    environment.prod.ts
  app/
    app.component.ts
    app.routes.ts
    features/
      home/
        home.component.ts
      projects/
        projects.component.ts</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>app.routes.ts</strong> holds your route config.</p>
</li>
<li>
<p>Each feature gets its own folder with a standalone component.</p>
</li>
<li>
<p>environments holds build-time configuration.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_simplified_bootstrapping_with_bootstrapapplication">Simplified bootstrapping with bootstrapApplication</h3>
<div class="paragraph">
<p>Standalone components and functional providers eliminate boilerplate. The entry point is lean and explicit.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { provideHttpClient, HttpInterceptorFn, withInterceptors } from '@angular/common/http';
import { provideAnimations } from '@angular/platform-browser/animations';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';

// Example functional interceptor (adds a version header)
const versionHeaderInterceptor: HttpInterceptorFn = (req, next) =&gt;
  next(req.clone({ setHeaders: { 'X-App-Version': '1.0.0' } }));

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes, withComponentInputBinding()),
    provideHttpClient(withInterceptors([versionHeaderInterceptor])),
    provideAnimations(),
    // If you generated the project with --ssr, enable hydration:
    // provideClientHydration(),
  ],
}).catch(err =&gt; console.error(err));</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>provideRouter</strong> wires your routing without a root NgModule.</p>
</li>
<li>
<p>provideHttpClient configures HttpClient with tree-shakable features like withInterceptors.</p>
</li>
<li>
<p>provideAnimations enables Angular animations globally.</p>
</li>
<li>
<p>withComponentInputBinding lets you bind route params/data directly to component inputs.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_routing_with_lazy_standalone_components">Routing with lazy standalone components</h3>
<div class="paragraph">
<p>Define routes in a single place and lazy-load components with loadComponent.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/app.routes.ts
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: '',
    loadComponent: () =&gt;
      import('./features/home/home.component').then(m =&gt; m.HomeComponent),
    title: 'Home',
  },
  {
    path: 'projects',
    loadComponent: () =&gt;
      import('./features/projects/projects.component').then(m =&gt; m.ProjectsComponent),
    title: 'Projects',
  },
  { path: '**', redirectTo: '' },
];</code></pre>
</div>
</div>
<div class="paragraph">
<p>This setup is fast to read and easy to evolve. Each path points directly at a standalone component without an intermediate NgModule.</p>
</div>
</div>
<div class="sect2">
<h3 id="_a_minimal_root_component">A minimal root component</h3>
<div class="paragraph">
<p>Keep your root component focused on layout and navigation.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/app.component.ts
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, RouterLink, RouterLinkActive],
  styles: [`
    nav { display: flex; gap: 1rem; padding: 1rem; border-bottom: 1px solid #eee; }
    a.active { font-weight: 600; text-decoration: underline; }
    main { padding: 1rem; }
  `],
  template: `
    &lt;nav&gt;
      &lt;a routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }"&gt;Home&lt;/a&gt;
      &lt;a routerLink="/projects" routerLinkActive="active"&gt;Projects&lt;/a&gt;
    &lt;/nav&gt;
    &lt;main&gt;
      &lt;router-outlet /&gt;
    &lt;/main&gt;
  `,
})
export class AppComponent {}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_build_a_real_feature_home_with_forms_and_new_control_flow">Build a real feature: Home with forms and new control flow</h3>
<div class="paragraph">
<p>Use reactive forms and the modern control flow syntax (@if, @for) to keep templates expressive and predictable.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/features/home/home.component.ts
import { Component, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';

type Project = { id: number; name: string };

@Component({
  imports: [ReactiveFormsModule],
  styles: [`
    form { display: flex; gap: 0.5rem; margin: 1rem 0; }
    input { min-width: 240px; }
    ul { padding-left: 1.25rem; }
  `],
  template: `
    &lt;h2&gt;Welcome&lt;/h2&gt;

    &lt;form [formGroup]="searchForm" (ngSubmit)="onSearch()"&gt;
      &lt;input formControlName="q" type="text" placeholder="Search projects" /&gt;
      &lt;button type="submit"&gt;Search&lt;/button&gt;
      &lt;button type="button" (click)="reset()"&gt;Reset&lt;/button&gt;
    &lt;/form&gt;

    @if (results().length === 0) {
      &lt;p&gt;No results found.&lt;/p&gt;
    } @else {
      &lt;ul&gt;
        @for (p of results(); track p.id) {
          &lt;li&gt;{{ p.name }}&lt;/li&gt;
        }
      &lt;/ul&gt;
    }
  `,
})
export class HomeComponent {
  private readonly allProjects: Project[] = [
    { id: 1, name: 'Roadmap' },
    { id: 2, name: 'UI Kit' },
    { id: 3, name: 'Infra' },
  ];

  results = signal&lt;Project[]&gt;(this.allProjects);

  constructor(private fb: FormBuilder) {}

  searchForm = this.fb.nonNullable.group({ q: '' });

  onSearch(): void {
    const q = this.searchForm.value.q?.toLowerCase() ?? '';
    this.results.set(
      this.allProjects.filter(p =&gt; p.name.toLowerCase().includes(q))
    );
  }

  reset(): void {
    this.searchForm.reset({ q: '' });
    this.results.set(this.allProjects);
  }
}</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>signal gives you ergonomic local state without services when you don’t need them.</p>
</li>
<li>
<p>The new control flow removes structural directive noise while remaining explicit.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_a_lazy_projects_page">A lazy projects page</h3>
<div class="paragraph">
<p>Keep feature components focused and stateless by default.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/features/projects/projects.component.ts
import { Component } from '@angular/core';

@Component({
  template: `
    &lt;h2&gt;Projects&lt;/h2&gt;
    &lt;p&gt;This is a lazy-loaded page. Add tables, filters, or charts here.&lt;/p&gt;
  `,
})
export class ProjectsComponent {}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The route configuration we defined earlier will load this component on demand.</p>
</div>
</div>
<div class="sect2">
<h3 id="_http_setup_with_functional_interceptors">HTTP setup with functional interceptors</h3>
<div class="paragraph">
<p>You already provided HttpClient in main.ts. Add domain-specific concerns via functional interceptors as your app grows (auth tokens, correlation IDs, error normalization). They compose with withInterceptors and stay tree-shakable.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// Example: src/app/core/auth.interceptor.ts (optional)
import { HttpInterceptorFn } from '@angular/common/http';

export const authInterceptor: HttpInterceptorFn = (req, next) =&gt; {
  const token = localStorage.getItem('token');
  return next(token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req);
};

// Then in main.ts:
// provideHttpClient(withInterceptors([authInterceptor, versionHeaderInterceptor]))</code></pre>
</div>
</div>
<div class="paragraph">
<p>Keep cross-cutting code small, testable, and colocated in core/.</p>
</div>
</div>
<div class="sect2">
<h3 id="_environment_driven_configuration">Environment-driven configuration</h3>
<div class="paragraph">
<p>Use build-time environments for API base URLs and toggles. The CLI swaps files based on configuration.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/environments/environment.ts
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000/api',
};

// src/environments/environment.prod.ts
export const environment = {
  production: true,
  apiUrl: 'https://api.example.com',
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Access where needed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// Anywhere in app code
import { environment } from '../environments/environment';
// http.get(`${environment.apiUrl}/projects`)</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_cli_commands_youll_use_daily">CLI commands you’ll use daily</h3>
<div class="ulist">
<ul>
<li>
<p>Generate features: ng g component app/features/activity</p>
</li>
<li>
<p>Add utilities: ng g interceptor core/logging</p>
</li>
<li>
<p>Run locally: ng serve</p>
</li>
<li>
<p>Build for production: ng build --configuration production</p>
</li>
<li>
<p>Run unit tests: ng test</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The Angular CLI keeps project setup consistent while remaining flexible.</p>
</div>
</div>
<div class="sect2">
<h3 id="_optional_server_side_rendering_ssr">Optional: Server-side rendering (SSR)</h3>
<div class="paragraph">
<p>If you create your project with --ssr, the CLI scaffolds an SSR server and hydration for you. In main.ts, include provideClientHydration() so the browser picks up the server-rendered DOM without re-rendering. SSR improves Time to First Byte (TTFB), SEO, and perceived performance for content-heavy routes.</p>
</div>
</div>
<div class="sect2">
<h3 id="_why_this_structure_works">Why this structure works</h3>
<div class="ulist">
<ul>
<li>
<p>Standalone components reduce indirection and speed up onboarding.</p>
</li>
<li>
<p>A single routes file gives you a map of the app at a glance.</p>
</li>
<li>
<p>Providers in main.ts make cross-cutting behavior explicit.</p>
</li>
<li>
<p>Feature-first folders keep implementation details close to their templates and styles.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_troubleshooting_and_tips">Troubleshooting and tips</h3>
<div class="ulist">
<ul>
<li>
<p>Type errors on control flow (@if/@for): ensure your component template uses the new Angular control flow (Angular 17+). No extra imports are needed.</p>
</li>
<li>
<p>RouterLinkActive not working on root: pass [routerLinkActiveOptions]="{ exact: true }" for the root link.</p>
</li>
<li>
<p>Interceptor order: interceptors run in the order provided for requests, and in reverse for responses. Put auth/correlation early; place global error handling last to see the final response state.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_conclusion">Conclusion</h3>
<div class="paragraph">
<p>Angular 20 cuts the ceremony: standalone components by default, functional providers, and minimal bootstrapping. Organize by feature, keep routes clear, and scale without the bloat. The CLI does the grunt work, you build features.</p>
</div>
</div>
<div class="sect2">
<h3 id="_next_steps">Next Steps</h3>
<div class="ulist">
<ul>
<li>
<p>Add a core/ directory for cross-cutting concerns (interceptors, guards, tokens).</p>
</li>
<li>
<p>Introduce a shared/ library for reusable UI primitives.</p>
</li>
<li>
<p>Wire HttpClient to a real backend and centralize API calls behind a data-access service.</p>
</li>
<li>
<p>Enable SSR (--ssr) and hydration for content-rich pages.</p>
</li>
<li>
<p>Adopt signals in more places thoughtfully: state local to a component is a good fit; shared, cross-route state still belongs in services.</p>
</li>
</ul>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Routing in Angular 20: Basics to Navigation Guards</title>
		<link>https://blog.lunatech.com//posts/2025-10-22-routing-in-angular-20-basics-to-navigation-guards</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-10-22T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[Beginner]]></category>
                }
             {
            <category><![CDATA[angular router]]></category>
                }
             {
            <category><![CDATA[navigation]]></category>
                }
             {
            <category><![CDATA[route guards]]></category>
                }
             {
            <category><![CDATA[async redirects]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-10-22-routing-in-angular-20-basics-to-navigation-guards</guid>

					<description>
                        <![CDATA[ Master client-side routing with Angular’s Router. Learn route configuration, navigation, guards, and Angular 20’s asynchronous redirect improvements.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Master client-side routing with Angular’s Router. Learn route configuration, navigation, guards, and Angular 20’s asynchronous redirect improvements.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_why_the_router_still_matters">Why the Router still matters</h3>
<div class="paragraph">
<p>Routing is the backbone of user flow. It defines how screens load, what data they need, and how access is enforced. A reliable setup pays off when your app scales and your team grows. In Angular 20, the Angular Router keeps moving in the right direction: clearer configuration, better async flows, and ergonomics that prioritize maintainability.</p>
</div>
<div class="paragraph">
<p>This guide walks through a practical baseline: route configuration, links, programmatic navigation, route guards, and async redirects, all with standalone components and functional APIs.</p>
</div>
</div>
<div class="sect2">
<h3 id="_a_minimal_modern_router_setup">A minimal, modern router setup</h3>
<div class="paragraph">
<p>Use standalone APIs and <strong>provideRouter</strong> for a clean bootstrap.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(
      routes,
      withPreloading(PreloadAllModules),
    ),
  ],
});</code></pre>
</div>
</div>
<div class="paragraph">
<p>Define your routes in a dedicated file. Prefer lazy-loading to keep initial bundles lean.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// app/app.routes.ts
import { Routes } from '@angular/router';
import { authCanActivate, authCanMatch, unsavedCanDeactivate } from './auth/guards';

export const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },

  {
    path: 'home',
    title: 'Home',
    loadComponent: () =&gt; import('./features/home/home.component').then(m =&gt; m.HomeComponent),
  },
  {
    path: 'dashboard',
    title: 'Dashboard',
    canActivate: [authCanActivate],
    loadComponent: () =&gt; import('./features/dashboard/dashboard.component').then(m =&gt; m.DashboardComponent),
  },
  {
    path: 'projects',
    canMatch: [authCanMatch],
    loadChildren: () =&gt; import('./features/projects/projects.routes').then(m =&gt; m.PROJECTS_ROUTES),
  },
  {
    path: 'settings',
    title: 'Settings',
    canDeactivate: [unsavedCanDeactivate],
    loadComponent: () =&gt; import('./features/settings/settings.component').then(m =&gt; m.SettingsComponent),
  },
  {
    path: 'login',
    title: 'Sign in',
    loadComponent: () =&gt; import('./features/auth/login.component').then(m =&gt; m.LoginComponent),
  },
  {
    path: '**',
    title: 'Not Found',
    loadComponent: () =&gt; import('./shared/not-found/not-found.component').then(m =&gt; m.NotFoundComponent),
  },
];</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_the_application_shell_links_and_outlet">The application shell: links and outlet</h3>
<div class="paragraph">
<p>Make navigation obvious and accessible. Use RouterLink and RouterLinkActive for feedback.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;!-- app/app.component.html --&gt;
&lt;header class="app-header"&gt;
  &lt;nav&gt;
    &lt;a routerLink="/home" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }"&gt;Home&lt;/a&gt;
    &lt;a routerLink="/dashboard" routerLinkActive="active"&gt;Dashboard&lt;/a&gt;
    &lt;a routerLink="/projects" routerLinkActive="active"&gt;Projects&lt;/a&gt;
    &lt;a routerLink="/settings" routerLinkActive="active"&gt;Settings&lt;/a&gt;
  &lt;/nav&gt;
&lt;/header&gt;

&lt;main&gt;
  &lt;router-outlet&gt;&lt;/router-outlet&gt;
&lt;/main&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>RouterLink keeps your templates declarative; RouterOutlet hosts the matched view. For accessibility and UX, the active class communicates where the user is during navigation.</p>
</div>
</div>
<div class="sect2">
<h3 id="_a_realistic_feature_route_with_params_and_lazy_loading">A realistic feature route with params and lazy-loading</h3>
<div class="paragraph">
<p>For features like Projects, lazy load the route definition and child screens.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// features/projects/projects.routes.ts
import { Routes } from '@angular/router';

export const PROJECTS_ROUTES: Routes = [
  {
    path: '',
    title: 'Projects',
    loadComponent: () =&gt; import('./list/projects-list.component').then(m =&gt; m.ProjectsListComponent),
  },
  {
    path: ':id',
    title: 'Project Details',
    loadComponent: () =&gt; import('./details/project-details.component').then(m =&gt; m.ProjectDetailsComponent),
  },
];</code></pre>
</div>
</div>
<div class="paragraph">
<p>In a details component, read route params. Use clean, testable patterns.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// features/projects/details/project-details.component.ts
import { Component, computed, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { ProjectService } from '../data/project.service';

@Component({
  standalone: true,
  selector: 'app-project-details',
  template: `
    @if (project(); as data) {
      &lt;h2&gt;{{ data.name }}&lt;/h2&gt;
      &lt;button (click)="goBack()"&gt;Back&lt;/button&gt;
    } @else {
      &lt;p&gt;Project not found.&lt;/p&gt;
    }
  `,
})
export class ProjectDetailsComponent {
  private route = inject(ActivatedRoute);
  private router = inject(Router);
  private service = inject(ProjectService);

  private paramMap = toSignal(this.route.paramMap, { initialValue: this.route.snapshot.paramMap });
  id = computed(() =&gt; this.paramMap()?.get('id') ?? null);

  project = toSignal(this.service.getProjectStream(this.route.paramMap), { initialValue: null });

  goBack() {
    this.router.navigate(['../'], { relativeTo: this.route });
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Use toSignal when a component benefits from reactive values in the template.</p>
</li>
<li>
<p>Keep navigation relative to avoid hardcoding URLs.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_programmatic_navigation_that_reads_well">Programmatic navigation that reads well</h3>
<div class="paragraph">
<p>When you need to route from code, favor clarity and explicitness.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// features/auth/login.component.ts (snippet)
import { Component, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Component({
  standalone: true,
  template: `
    &lt;form (ngSubmit)="login()"&gt;
      &lt;!-- form fields --&gt;
      &lt;button type="submit"&gt;Sign in&lt;/button&gt;
    &lt;/form&gt;
  `,
})
export class LoginComponent {
  private router = inject(Router);
  private route = inject(ActivatedRoute);
  private auth = inject(AuthService);

  async login() {
    await this.auth.signIn();
    const redirect = this.route.snapshot.queryParamMap.get('redirect') || '/dashboard';
    this.router.navigateByUrl(redirect, { replaceUrl: true, state: { from: 'login' } });
  }
}</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>navigate and navigateByUrl are both fine; navigate works with command arrays and relative routes.</p>
</li>
<li>
<p>replaceUrl avoids filling history with transient steps like login.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_route_guards_protect_match_and_confirm">Route guards: protect, match, and confirm</h3>
<div class="paragraph">
<p>Functional guards are terse, testable, and DI-friendly. Use canActivate for already-loaded routes and canMatch to gate access before lazy-loading. Use canDeactivate to protect against losing changes.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// app/auth/guards.ts
import { inject } from '@angular/core';
import { CanActivateFn, CanDeactivateFn, CanMatchFn, Router, UrlSegment, Route } from '@angular/router';
import { AuthService } from './auth.service';

export const authCanActivate: CanActivateFn = (_route, state) =&gt; {
  const auth = inject(AuthService);
  const router = inject(Router);
  if (auth.isLoggedIn()) return true;
  // Return a UrlTree to redirect without throwing
  return router.createUrlTree(['/login'], { queryParams: { redirect: state.url } });
};

export const authCanMatch: CanMatchFn = (route: Route, segments: UrlSegment[]) =&gt; {
  const auth = inject(AuthService);
  const router = inject(Router);
  if (auth.isLoggedIn()) return true;

  const attempted = '/' + segments.map(s =&gt; s.path).join('/');
  return router.createUrlTree(['/login'], { queryParams: { redirect: attempted } });
};

export const unsavedCanDeactivate: CanDeactivateFn&lt;{ hasUnsavedChanges(): boolean }&gt; = (component) =&gt; {
  return component.hasUnsavedChanges()
    ? confirm('You have unsaved changes. Leave this page?')
    : true;
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Returning a UrlTree is the most ergonomic way to redirect from guards.</p>
</li>
<li>
<p>Prefer canMatch for lazy-loaded feature entries. It prevents loading code the user can’t access.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_async_redirects_in_angular_20">Async redirects in Angular 20</h3>
<div class="paragraph">
<p>Redirects are often conditional and data-driven. Angular 20 refines ergonomics for async redirects by allowing redirect functions to return a Promise or Observable of a UrlTree, keeping logic declarative in the route table. When you need Dependency Injection, the function executes in a proper injection context.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// app/app.routes.ts (excerpt showing async redirect)
import { Router, Routes } from '@angular/router';
import { inject } from '@angular/core';
import { AuthService } from './auth/auth.service';

export const routes: Routes = [
  // ...
  {
    path: 'start',
    // Async redirect based on login status
    redirectTo: async () =&gt; {
      const auth = inject(AuthService);
      const router = inject(Router);
      const isLoggedIn = await auth.isLoggedInOnce(); // e.g., resolves after token refresh
      return isLoggedIn
        ? router.createUrlTree(['/dashboard'])
        : router.createUrlTree(['/login'], { queryParams: { redirect: '/start' } });
    },
    pathMatch: 'full',
  },
  // ...
];</code></pre>
</div>
</div>
<div class="paragraph">
<p>If your team prefers explicit control (or for compatibility), use canMatch to perform the same async decision and return a UrlTree. Both approaches keep “redirect intent” within the routing layer, preserving a clear separation from UI.</p>
</div>
</div>
<div class="sect2">
<h3 id="_handling_404s_and_fallbacks">Handling 404s and fallbacks</h3>
<div class="paragraph">
<p>Keep a final catch-all route at the end. Make the not-found component tiny and isolated.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// shared/not-found/not-found.component.ts
import { Component } from '@angular/core';

@Component({
  standalone: true,
  template: `
    &lt;h2&gt;Page not found&lt;/h2&gt;
    &lt;p&gt;The page you’re looking for doesn’t exist.&lt;/p&gt;
    &lt;a routerLink="/home"&gt;Go to Home&lt;/a&gt;
  `,
})
export class NotFoundComponent {}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_developer_experience_tips_that_scale">Developer experience tips that scale</h3>
<div class="ulist">
<ul>
<li>
<p>Title and data: Use the route title for sensible defaults. Keep route data small and serializable.</p>
</li>
<li>
<p>Preloading: withPreloading(PreloadAllModules) improves perceived speed after the first screen.</p>
</li>
<li>
<p>Guard reuse: Share a single predicate behind multiple guard types (e.g., canActivate and canMatch) to avoid drift.</p>
</li>
<li>
<p>UrlTree over side effects: Prefer returning UrlTree over imperative router.navigate inside guards.</p>
</li>
<li>
<p>Relative navigation: Favor relativeTo where possible to avoid brittle absolute paths.</p>
</li>
<li>
<p>Observability: Listen to router.events for tracing NavigationStart, NavigationEnd, NavigationCancel when debugging.</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// Simple router event logging helper (dev only)
import { filter } from 'rxjs';
import { Router, NavigationStart, NavigationEnd, NavigationCancel } from '@angular/router';

export function logNavigation(router: Router) {
  router.events
    .pipe(filter(e =&gt; e instanceof NavigationStart || e instanceof NavigationEnd || e instanceof NavigationCancel))
    .subscribe(e =&gt; console.debug('[router]', e));
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_common_pitfalls_and_guardrails">Common pitfalls and guardrails</h3>
<div class="ulist">
<ul>
<li>
<p>Infinite redirect loops: Always check target vs current URL when redirecting conditionally. Returning the same UrlTree repeatedly will stall navigation.</p>
</li>
<li>
<p>Missing pathMatch: For empty-path redirects, pathMatch: 'full' prevents partial matches from hijacking nested routes.</p>
</li>
<li>
<p>Eager vs lazy: Use canMatch for feature entries to avoid loading code for unauthorized users.</p>
</li>
<li>
<p>Query params and state: Preserve user intent via redirect query params. Clear them after successful navigation if they’re transient.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_putting_it_together_a_cohesive_flow">Putting it together: a cohesive flow</h3>
<div class="ulist">
<ul>
<li>
<p>Users hitting /start are asynchronously redirected based on auth state using async redirects.</p>
</li>
<li>
<p>Unauthenticated users attempting /projects are intercepted by canMatch and sent to /login with a redirect back.</p>
</li>
<li>
<p>Settings protects against accidental loss via canDeactivate.</p>
</li>
<li>
<p>Dashboard and Projects load lazily, preloaded after the first screen.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This balances UX and performance while keeping the routing layer the single source of truth for navigation logic.</p>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A well-structured router is more than a URL switchboard, it’s an agreement about flow, access, and intent. Angular’s modern APIs make routing readable and testable: standalone routes, functional route guards, lazy-loading, and async redirects that keep decisions close to configuration. When your code communicates clearly, your team moves faster and makes fewer mistakes.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_next_steps">Next Steps</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Extract guard predicates into pure functions and unit test them with dependency mocks.</p>
</li>
<li>
<p>Add a data resolver where you need the route to wait for critical data before rendering.</p>
</li>
<li>
<p>Introduce a prefetch strategy for specific features, or preload on hover using quicklink-style heuristics.</p>
</li>
<li>
<p>Explore view transitions with router integration to smooth screen changes.</p>
</li>
<li>
<p>Audit routes for consistent titles, data contracts, and error handling paths.</p>
</li>
</ul>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Data Binding in Angular: Templates, Interpolation, and Property/Event Binding</title>
		<link>https://blog.lunatech.com//posts/2025-10-15-data-binding-in-angular-templates-interpolation-and-propertyevent-binding</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-10-15T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[Beginner]]></category>
                }
             {
            <category><![CDATA[property binding]]></category>
                }
             {
            <category><![CDATA[event binding]]></category>
                }
             {
            <category><![CDATA[interpolation]]></category>
                }
             {
            <category><![CDATA[template syntax]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-10-15-data-binding-in-angular-templates-interpolation-and-propertyevent-binding</guid>

					<description>
                        <![CDATA[ Data binding is the heartbeat of Angular templates. Learn how data flows between components and templates using interpolation, property binding, event binding, and two-way binding. This topic also introduces new Angular 20 template features like template literals. We’ll keep the focus practical: clear patterns, minimal surprises, and maintainable code that scales.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Data binding is the heartbeat of Angular templates. Learn how data flows between components and templates using interpolation, property binding, event binding, and two-way binding. This topic also introduces new Angular 20 template features like template literals. We’ll keep the focus practical: clear patterns, minimal surprises, and maintainable code that scales.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_the_mental_model_unidirectional_data_flow_well_timed_feedback">The mental model: unidirectional data flow, well-timed feedback</h3>
<div class="ulist">
<ul>
<li>
<p>From component to view: interpolation and property binding render state.</p>
</li>
<li>
<p>From view to component: event binding captures user intent.</p>
</li>
<li>
<p>Two-way binding is a convenience that composes the two, not a separate mechanism.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Favor predictable one-way flows; reach for two-way when it improves clarity without hiding complexity.</p>
</div>
</div>
<div class="sect2">
<h3 id="_interpolation_simple_readable_one_way_display">Interpolation: simple, readable, one-way display</h3>
<div class="paragraph">
<p>Interpolation renders values into text nodes using template syntax like {{ &#8230;&#8203; }}. It’s ideal for human-readable content.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;h2&gt;{{ title }}&lt;/h2&gt;
&lt;p&gt;Welcome, {{ user?.name ?? 'Guest' }}.&lt;/p&gt;
&lt;p&gt;Subtotal: {{ price | currency: 'USD' }}&lt;/p&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Guidelines:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Keep expressions simple. Avoid calling methods that do non-trivial work.</p>
</li>
<li>
<p>Use pipes for presentation logic (formatting, slicing, etc.).</p>
</li>
<li>
<p>Use the safe-navigation operator (?.) to avoid null/undefined errors at render time.</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="_angular_20_template_literals_in_expressions">Angular 20 template literals in expressions</h4>
<div class="paragraph">
<p>Angular 20 enables JavaScript-style template literals inside template expressions for more expressive string composition.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;h2&gt;{{ `${greeting}, ${user?.firstName || 'friend'}!` }}&lt;/h2&gt;
&lt;button [attr.aria-label]="`Open details for ${item.title}`"&gt;Open&lt;/button&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Use them for readable, localized strings or ARIA attributes. Keep them concise. If you’re building complex messages, consider a dedicated formatter or i18n.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_property_binding_write_to_dom_and_component_inputs">Property binding: write to DOM and component inputs</h3>
<div class="paragraph">
<p>Property binding uses square brackets to set DOM properties, ARIA attributes, styles, classes, and child component inputs.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;!-- DOM properties --&gt;
&lt;input [value]="query()" [disabled]="isSubmitting()" /&gt;

&lt;!-- Attributes and accessibility --&gt;
&lt;button [attr.aria-pressed]="isActive" [attr.data-id]="item.id"&gt;Toggle&lt;/button&gt;

&lt;!-- Classes and styles --&gt;
&lt;div [class.active]="isActive" [style.width.px]="panelWidth"&gt;&lt;/div&gt;

&lt;!-- Child component inputs --&gt;
&lt;app-avatar [src]="user.photoUrl" [alt]="user.name" [size]="64"&gt;&lt;/app-avatar&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Under the hood, Angular binds to the actual property when available (safer and more correct than raw attributes). Use [attr.*] only when there is no matching property.</p>
</div>
<div class="sect3">
<h4 id="_signals_play_nicely_with_bindings">Signals play nicely with bindings</h4>
<div class="paragraph">
<p>Signals provide push-based reactivity. Call them in templates to read their current value.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';

@Component({
  selector: 'app-search',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    &lt;label&gt;
      Query:
      &lt;input [value]="query()" (input)="onInput($event)" placeholder="Type to search..." /&gt;
    &lt;/label&gt;

    @if (filtered().length === 0) {
      &lt;p&gt;No results&lt;/p&gt;
    } @else {
      &lt;ul&gt;
        @for (item of filtered(); track item) {
          &lt;li&gt;{{ item }}&lt;/li&gt;
        }
      &lt;/ul&gt;
    }
  `
})
export class SearchComponent {
  readonly items = signal(['apple', 'banana', 'citrus', 'date', 'elderberry']);
  readonly query = signal('');
  readonly filtered = computed(() =&gt;
    this.items().filter(v =&gt; v.toLowerCase().includes(this.query().toLowerCase()))
  );

  onInput(event: Event) {
    const input = event.target as HTMLInputElement;
    this.query.set(input.value);
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Property binding [value]="query()" reads the signal.</p>
</li>
<li>
<p>Event binding (input)="&#8230;&#8203;" updates the signal.</p>
</li>
<li>
<p>Built-in control flow (@if and @for) keeps the template declarative and fast.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_event_binding_user_intent_back_to_the_component">Event binding: user intent back to the component</h3>
<div class="paragraph">
<p>Event binding uses parentheses to listen to DOM or component events.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;button (click)="toggle()"&gt;{{ isOpen ? 'Close' : 'Open' }}&lt;/button&gt;
&lt;input (keydown.enter)="submit()" /&gt;
&lt;input (input)="onInput($event)" /&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Type your handlers for safety and clarity.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">toggle(): void {
  this.isOpen = !this.isOpen;
}

submit(): void {
  if (!this.formValid) return;
  this.save();
}

onInput(event: Event): void {
  const target = event.target as HTMLInputElement;
  this.value = target.value;
}</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>Prefer specific event names like keydown.enter for intent-revealing handlers.</p>
</li>
<li>
<p>Avoid expensive work inside template expressions; do it in component methods or computed signals.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_two_way_binding_when_it_helps_use_it_intentionally">Two-way binding: when it helps, use it intentionally</h3>
<div class="paragraph">
<p>Two-way binding composes property binding and event binding into a single banana-in-a-box syntax.</p>
</div>
<div class="sect3">
<h4 id="_with_forms_ngmodel">With forms (ngModel)</h4>
<div class="paragraph">
<p>This is convenient in simple forms. Import FormsModule in standalone components.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-preferences',
  standalone: true,
  imports: [FormsModule],
  template: `
    &lt;label&gt;Nickname: &lt;input [(ngModel)]="nickname" /&gt;&lt;/label&gt;
    &lt;label&gt;
      &lt;input type="checkbox" [(ngModel)]="emailOptIn" /&gt;
      Email me updates
    &lt;/label&gt;
    &lt;p&gt;Preview: {{ nickname }} (opt-in: {{ emailOptIn }})&lt;/p&gt;
  `
})
export class PreferencesComponent {
  nickname = '';
  emailOptIn = true;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>With signals, bridge two-way binding by pairing [ngModel] and (ngModelChange):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;input [ngModel]="query()" (ngModelChange)="query.set($event)" /&gt;</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_custom_two_way_binding_for_child_components">Custom two-way binding for child components</h4>
<div class="paragraph">
<p>Define a pair of Input and Output with the Change suffix. Angular will recognize [(value)].</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-rating',
  standalone: true,
  imports: [CommonModule],
  template: `
    &lt;div class="stars"&gt;
      &lt;button *ngFor="let s of [1,2,3,4,5]"
              type="button"
              [class.filled]="s &lt;= value"
              (click)="setValue(s)"
              [attr.aria-label]="'Set rating to ' + s"&gt;
        ★
      &lt;/button&gt;
    &lt;/div&gt;
  `,
  styles: [`.filled { color: #f59e0b; } button { background:none; border:none; font-size:1.25rem; cursor:pointer; }`]
})
export class RatingComponent {
  @Input() value = 0;
  @Output() valueChange = new EventEmitter&lt;number&gt;();

  setValue(v: number) {
    this.value = v;
    this.valueChange.emit(v);
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Parent usage:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;app-rating [(value)]="product.rating"&gt;&lt;/app-rating&gt;
&lt;p&gt;Current rating: {{ product.rating }}&lt;/p&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Tip: If your project uses the signal-based inputs API, the model() helper can reduce boilerplate. The classic pair above remains broadly compatible and explicit.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_template_syntax_patterns_that_scale">Template syntax patterns that scale</h3>
<div class="ulist">
<ul>
<li>
<p>Keep expressions pure and cheap. Avoid calling functions that allocate arrays or perform filtering on each change detection; use computed signals or memoized selectors.</p>
</li>
<li>
<p>Bind to properties, not attributes. Prefer [value], [disabled], [checked] over [attr.value], except when no property exists.</p>
</li>
<li>
<p>Use track with @for to avoid re-rendering stable items:
@for (item of items; track item.id) { &#8230;&#8203; }</p>
</li>
<li>
<p>For [innerHTML], sanitize or trust only safe content. Angular’s DomSanitizer exists for exceptional cases—prefer plain text whenever possible.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_angular_20_template_literal_examples_in_context">Angular 20 template literal examples in context</h3>
<div class="paragraph">
<p>Use template literals where they improve clarity, especially for ARIA and labeling.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;!-- Readable, localized-friendly labels --&gt;
&lt;button
  type="button"
  [attr.aria-label]="`${isPlaying ? 'Pause' : 'Play'} ${track.title}`"
  (click)="togglePlay()"&gt;
  {{ isPlaying ? 'Pause' : 'Play' }}
&lt;/button&gt;

&lt;!-- Combining with pipes --&gt;
&lt;p&gt;{{ `Hello, ${user?.name || 'Guest'}` | titlecase }}&lt;/p&gt;

&lt;!-- Attributes that aren’t DOM properties --&gt;
&lt;a [attr.data-test-id]="`link-${link.id}`" [href]="link.url"&gt;{{ link.title }}&lt;/a&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Keep logic minimal; push complex decisions into the component or computed signals for testability.</p>
</div>
</div>
<div class="sect2">
<h3 id="_a_cohesive_example_binding_the_pieces">A cohesive example: binding the pieces</h3>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RatingComponent } from './rating.component';

@Component({
  selector: 'app-product-card',
  standalone: true,
  imports: [CommonModule, FormsModule, RatingComponent],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    &lt;article class="card"&gt;
      &lt;header&gt;
        &lt;h3&gt;{{ product().name }}&lt;/h3&gt;
        &lt;p class="price"&gt;{{ product().price | currency:'USD' }}&lt;/p&gt;
      &lt;/header&gt;

      &lt;label [attr.aria-label]="`Quantity for ${product().name}`"&gt;
        Qty:
        &lt;input type="number"
               min="1"
               [ngModel]="qty()"
               (ngModelChange)="qty.set($event)" /&gt;
      &lt;/label&gt;

      &lt;app-rating [(value)]="rating"&gt;&lt;/app-rating&gt;

      &lt;p&gt;{{ description }}&lt;/p&gt;

      &lt;button type="button"
              class="add"
              [disabled]="isSubmitting()"
              (click)="addToCart()"&gt;
        {{ isSubmitting() ? 'Adding…' : 'Add to cart' }}
      &lt;/button&gt;
    &lt;/article&gt;
  `,
  styles: [`.card{border:1px solid #e5e7eb;border-radius:.5rem;padding:1rem}.price{color:#374151}.add{margin-top:.75rem}`]
})
export class ProductCardComponent {
  readonly product = signal({ id: 1, name: 'Noise-canceling Headphones', price: 199.99 });
  readonly qty = signal(1);
  rating = 4; // two-way bound to child
  readonly isSubmitting = signal(false);

  get description(): string {
    return `${this.product().name} — rated ${this.rating}/5 by our customers.`;
  }

  async addToCart() {
    this.isSubmitting.set(true);
    try {
      await fakeHttpPost({
        id: this.product().id,
        qty: this.qty(),
        rating: this.rating
      });
    } finally {
      this.isSubmitting.set(false);
    }
  }
}

function fakeHttpPost(payload: unknown) {
  return new Promise&lt;void&gt;(r =&gt; setTimeout(r, 500));
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>What you see:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Interpolation renders human-readable fields.</p>
</li>
<li>
<p>Property binding controls input state and disabled state.</p>
</li>
<li>
<p>Event binding processes clicks and model changes.</p>
</li>
<li>
<p>Two-way binding streamlines rating updates.</p>
</li>
<li>
<p>Template literals keep labels clear and accessible.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_conclusion">Conclusion</h3>
<div class="paragraph">
<p>Data binding is how intent flows through your Angular app. Interpolation and property binding project state. Event binding captures change. Two-way binding composes both when it reduces friction. With Angular 20’s template literal support, you can craft clearer strings and ARIA labels without sacrificing readability. Keep expressions simple, push complexity into components or computed signals, and lean on built-in control flow for performance.</p>
</div>
</div>
<div class="sect2">
<h3 id="_next_steps">Next Steps</h3>
<div class="ulist">
<ul>
<li>
<p>Audit a component for heavy template expressions. Move logic into computed signals or pure methods.</p>
</li>
<li>
<p>Add ARIA attributes with property binding and template literals to improve accessibility.</p>
</li>
<li>
<p>Refactor a custom control to support [(value)] using the input/output pair.</p>
</li>
<li>
<p>Explore Angular’s built-in control flow (@if, @for, @switch) to reduce directive boilerplate.</p>
</li>
<li>
<p>If your team uses signals broadly, standardize patterns for bridging with forms: [ngModel] + (ngModelChange) for crisp two-way behavior.</p>
</li>
</ul>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Getting Started with Angular 19: Your First Signals-Powered App</title>
		<link>https://blog.lunatech.com//posts/2025-10-12-getting-started-with-angular-19--your-first-signals-powered-app</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-10-12T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[angular basics]]></category>
                }
             {
            <category><![CDATA[signals]]></category>
                }
             {
            <category><![CDATA[reactive state]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-10-12-getting-started-with-angular-19--your-first-signals-powered-app</guid>

					<description>
                        <![CDATA[ Angular 19 makes signals a first-class, ergonomic way to manage reactive state—without the ceremony many of us associate with using RxJS for every problem. In this guide, you’ll build a small, production-quality feature using signals, computed values, and effects, sticking to Angular basics while practicing patterns you’ll reuse in real apps. Think of it as your “hello world” for signals, with enough structure to scale.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Angular 19 makes signals a first-class, ergonomic way to manage reactive state—without the ceremony many of us associate with using RxJS for every problem. In this guide, you’ll build a small, production-quality feature using signals, computed values, and effects, sticking to Angular basics while practicing patterns you’ll reuse in real apps. Think of it as your “hello world” for signals, with enough structure to scale.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_signals_for_your_first_angular_19_app">Why signals for your first Angular 19 app</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Signals shine when:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>You want local or feature-level state that’s easy to understand and test.</p>
</li>
<li>
<p>You prefer declarative data flow with minimal boilerplate.</p>
</li>
<li>
<p>You care about performance and predictable change detection.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Signals give you:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>signal(): a mutable value you set and read like a variable.</p>
</li>
<li>
<p>computed(): a derived value that automatically recalculates when dependencies change.</p>
</li>
<li>
<p>effect(): a side effect that runs when its dependent signals change (think persistence, logging, analytics).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>With the built-in control flow (@if, @for, @switch), Angular templates read signals naturally and concisely—no async pipe or manual subscriptions required.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_were_building">What we’re building</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A tiny yet complete “Tasks” feature:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Add tasks, toggle done, filter by status.</p>
</li>
<li>
<p>Persist to localStorage.</p>
</li>
<li>
<p>Derive stats via computed signals.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>We’ll use:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Standalone components.</p>
</li>
<li>
<p>inject() for dependency injection.</p>
</li>
<li>
<p>Signals for reactive state.</p>
</li>
<li>
<p>New template control flow.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you’re comfortable with Angular basics (components, templates, DI), you’re good to go.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_app_structure">App structure</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>TaskStore: a signals-powered service for state and business logic.</p>
</li>
<li>
<p>AppComponent: a standalone component that renders the UI and interacts with the store.</p>
</li>
<li>
<p>main.ts: bootstraps the app.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_taskstore_reactive_state_with_signals">TaskStore: reactive state with signals</h3>
<div class="paragraph">
<p>We’ll keep domain logic, mutations, and persistence here—a clean separation from the component.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Injectable, computed, effect, signal } from '@angular/core';

export type TaskFilter = 'all' | 'open' | 'done';

export interface Task {
  id: string;
  title: string;
  done: boolean;
}

function loadTasks(): Task[] {
  try {
    const raw = localStorage.getItem('tasks.v1');
    return raw ? JSON.parse(raw) as Task[] : [];
  } catch {
    return [];
  }
}

@Injectable({ providedIn: 'root' })
export class TaskStore {
  // Source signals
  private readonly tasks = signal&lt;Task[]&gt;(loadTasks());
  readonly filter = signal&lt;TaskFilter&gt;('all');

  // Derived reactive state
  readonly stats = computed(() =&gt; {
    const list = this.tasks();
    const done = list.filter(t =&gt; t.done).length;
    const open = list.length - done;
    return { total: list.length, open, done };
  });

  readonly filtered = computed(() =&gt; {
    const f = this.filter();
    const list = this.tasks();
    if (f === 'open') return list.filter(t =&gt; !t.done);
    if (f === 'done') return list.filter(t =&gt; t.done);
    return list;
  });

  // Persist tasks whenever they change
  private readonly persist = effect(() =&gt; {
    const current = this.tasks();
    localStorage.setItem('tasks.v1', JSON.stringify(current));
  });

  add(title: string) {
    const clean = title.trim();
    if (!clean) return;
    const newTask: Task = { id: crypto.randomUUID(), title: clean, done: false };
    this.tasks.update(list =&gt; [newTask, ...list]);
  }

  toggle(id: string) {
    this.tasks.update(list =&gt;
      list.map(t =&gt; (t.id === id ? { ...t, done: !t.done } : t))
    );
  }

  remove(id: string) {
    this.tasks.update(list =&gt; list.filter(t =&gt; t.id !== id));
  }

  clearDone() {
    this.tasks.update(list =&gt; list.filter(t =&gt; !t.done));
  }

  // Expose readonly getters where helpful
  get all() { return this.tasks.asReadonly(); }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Keep tasks private, expose asReadonly() if needed, and route all mutations through methods. That protects invariants and makes tests straightforward.</p>
</li>
<li>
<p>computed() caches until dependencies change, so stats and filtered are cheap to read in templates.</p>
</li>
<li>
<p>effect() is for side effects only. Don’t derive data there.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_appcomponent_template_first_with_control_flow">AppComponent: template-first with control flow</h3>
<div class="paragraph">
<p>The component stays lean: read signals, call store methods, and keep the markup honest. No subscriptions and no manual change detection.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { Component, inject } from '@angular/core';
import { TaskStore, TaskFilter } from './task.store';

@Component({
  selector: 'app-root',
  standalone: true,
  templateUrl: './app.component.html',
})
export class AppComponent {
  readonly store = inject(TaskStore);

  setFilter(f: TaskFilter) {
    this.store.filter.set(f);
  }

  add(input: HTMLInputElement) {
    this.store.add(input.value);
    input.value = '';
    input.focus();
  }
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;header class="app-header"&gt;
  &lt;h1&gt;Tasks (Signals)&lt;/h1&gt;
  &lt;p&gt;
    Total: {{ store.stats().total }}
    • Open: {{ store.stats().open }}
    • Done: {{ store.stats().done }}
  &lt;/p&gt;
&lt;/header&gt;

&lt;section class="task-create"&gt;
  &lt;input
    #title
    type="text"
    placeholder="Add a task and press Enter"
    (keyup.enter)="add(title)"
    aria-label="New task title" /&gt;
  &lt;button (click)="add(title)"&gt;Add&lt;/button&gt;
&lt;/section&gt;

&lt;nav class="filters"&gt;
  &lt;button (click)="setFilter('all')" [class.active]="store.filter() === 'all'"&gt;All&lt;/button&gt;
  &lt;button (click)="setFilter('open')" [class.active]="store.filter() === 'open'"&gt;Open&lt;/button&gt;
  &lt;button (click)="setFilter('done')" [class.active]="store.filter() === 'done'"&gt;Done&lt;/button&gt;
&lt;/nav&gt;

&lt;section class="task-list"&gt;
  @if (store.filtered().length === 0) {
    &lt;p class="empty"&gt;No tasks to show.&lt;/p&gt;
  } @else {
    &lt;ul&gt;
      @for (task of store.filtered(); track task.id) {
        &lt;li&gt;
          &lt;label&gt;
            &lt;input type="checkbox" [checked]="task.done" (change)="store.toggle(task.id)" /&gt;
            &lt;span [class.done]="task.done"&gt;{{ task.title }}&lt;/span&gt;
          &lt;/label&gt;
          &lt;button class="remove" (click)="store.remove(task.id)" aria-label="Remove task"&gt;✕&lt;/button&gt;
        &lt;/li&gt;
      }
    &lt;/ul&gt;
  }
&lt;/section&gt;

&lt;footer class="actions"&gt;
  &lt;button (click)="store.clearDone()" [disabled]="store.stats().done === 0"&gt;
    Clear completed
  &lt;/button&gt;
&lt;/footer&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>A few things to notice:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Reading a signal in a template uses function-call syntax: store.stats().</p>
</li>
<li>
<p>The new @if and @for syntax is concise and fast; track by a stable id to minimize DOM churn.</p>
</li>
<li>
<p>We avoid ngModel here to keep the example lean; use reactive forms if you need validation and composition.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_bootstrap">Bootstrap</h3>
<div class="paragraph">
<p>With standalone components, the bootstrap is pleasantly thin.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';

bootstrapApplication(AppComponent).catch(err =&gt; console.error(err));</code></pre>
</div>
</div>
<div class="paragraph">
<p>That’s it. No NgModule, no extra ceremony. In a larger app, you’d layer in provideRouter, HTTP, and other providers here.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_developer_experience_and_design_notes">Developer experience and design notes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>From real projects migrating to signals and the new control flow, a few principles keep teams productive:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Keep mutations small and intention-revealing.</p>
</li>
<li>
<p>add, toggle, remove, clearDone communicate behavior explicitly.</p>
</li>
<li>
<p>Encapsulate shape and invariants in your store; keep the component mostly declarative.</p>
</li>
<li>
<p>Use computed for any value you want to “feel like” state in the template.</p>
</li>
<li>
<p>stats and filtered are cheap to read and always consistent.</p>
</li>
<li>
<p>Avoid doing ad-hoc filtering in templates; it’s harder to optimize and test.</p>
</li>
<li>
<p>Reserve effect for I/O and cross-cutting behavior.</p>
</li>
<li>
<p>Persistence, analytics, message bus publishing—great uses of effect.</p>
</li>
<li>
<p>Don’t compute UI data inside effect; that’s what computed is for.</p>
</li>
<li>
<p>Prefer signals for local/feature reactive state, embrace RxJS where it fits.</p>
</li>
<li>
<p>Signals are excellent for UI state and domain mutations.</p>
</li>
<li>
<p>Streams still shine for event composition, websockets, and complex async flows.</p>
</li>
<li>
<p>Interop utilities exist if you need to bridge; start simple.</p>
</li>
<li>
<p>Track by stable ids in @for.</p>
</li>
<li>
<p>You’ll avoid unnecessary re-renders and improve perceived performance.</p>
</li>
<li>
<p>Keep templates dumb.</p>
</li>
<li>
<p>Let the store manage logic; your templates will stay readable, and testing gets easier.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_testing_the_store">Testing the store</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Signals play nicely with unit tests because there’s no hidden subscription machinery to manage.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Instantiate TaskStore directly, call methods, and assert on taskStore.filtered(), taskStore.stats(), etc.</p>
</li>
<li>
<p>If an effect writes to localStorage, consider injecting a light persistence adapter so you can stub it in tests. For this article’s simplicity, we wrote to localStorage directly; in production, prefer an injected storage port.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_where_this_scales">Where this scales</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This pattern scales surprisingly far:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Add tags or due dates? Extend Task and update computed accordingly.</p>
</li>
<li>
<p>Need a multi-page app? Provide routes and lazy-load feature components while keeping a small, focused store per feature.</p>
</li>
<li>
<p>Want undo/redo? Wrap mutations to capture patches and provide intent-level commands.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Signals help you move faster because the mental model is simple: read values, change values, derive values. It’s the right default for many UI flows.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_common_pitfalls_to_avoid">Common pitfalls to avoid</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Overusing effect for data derivation. If you find yourself setting signals inside an effect just to compute something, reach for computed instead.</p>
</li>
<li>
<p>Mixing many mutable signals in components. Prefer a single cohesive store per feature or sub-feature.</p>
</li>
<li>
<p>Forgetting to track by id in @for. It’s a small habit with big performance wins.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Getting started with Angular 19 and signals doesn’t require a framework rewrite. By leaning on a simple TaskStore and a lean component using the new control flow, we built a small but complete feature with clear reactive state and minimal boilerplate. This is the kind of foundation that keeps teams sane as apps grow—explicit mutations, derived state where it belongs, and templates that read like a story.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_next_steps">Next Steps</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Add a search signal and a computed that combines filter + search.</p>
</li>
<li>
<p>Extract persistence into an injected storage service and mock it in unit tests.</p>
</li>
<li>
<p>Introduce provideRouter and split the UI into feature routes.</p>
</li>
<li>
<p>Integrate reactive forms for validation on create/edit flows.</p>
</li>
<li>
<p>Explore interop with RxJS for server events or HTTP polling, using signals at the edges.</p>
</li>
<li>
<p>Measure with Angular DevTools and keep track-by rules tight as lists grow.</p>
</li>
</ul>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Terminal-first Mouseless Development Or How To Be A Hipster Engineer</title>
		<link>https://blog.lunatech.com//posts/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer</link>
		
		<dc:creator><![CDATA[]]></dc:creator>
        <pubDate>2025-07-11T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[beyond-the-code]]></category>
                }
             {
            <category><![CDATA[bash-to-the-feature]]></category>
                }
             {
            <category><![CDATA[vim]]></category>
                }
             {
            <category><![CDATA[tmux]]></category>
                }
             {
            <category><![CDATA[cli]]></category>
                }
             {
            <category><![CDATA[terminal]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer</guid>

					<description>
                        <![CDATA[ In this article, I'm going to give you a slightly different view on]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In this article, I&#8217;m going to give you a slightly different view on
something you do on a daily basis. A philosophy that encourages you to
only use what you really need, keeps you away from being distracted,
lets you think about what your problem really involves, and trust what
your fingers have learned instead of relying on visual representation.
That is what I call terminal-first mouseless development. I&#8217;ll
try to sell it to you by giving an overview of how you can benefit from it in
real life. Apart from the theory,
we are also going to see real applications of these approaches.
In particular, we will talk about <code>tmux</code> and <code>neovim</code> — industry standards for becoming a real
hipster developer.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_hipster_development">Hipster development?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We are all familiar with our IDEs, coupled with other tools for
tasks like database management (DBeaver), testing APIs (Postman), and
container management (Docker Desktop). Even though they provide an
extensive GUI, they are also quite rich in distracting elements.
Additionally, using multiple tools and navigating between them
means a lot of context switching as well as having quite a loaded
environment. If you say that your favorite IDE has everything
built-in, then it violates the philosophy of Unix, which says that it is
more idiomatic to use small tools that do one thing well rather than the
opposite. Sort of a single responsibility principle.</p>
</div>
<div class="paragraph">
<p>And here comes what I call &#8220;<strong>Terminal-first development</strong>&#8221;, but it can be
called by any other similar terms. Its core principle is that your terminal
should be your central hub for development tasks.
Instead of installing a new GUI application to solve a problem, the terminal-first
approach challenges you to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Decompose the problem into smaller, distinct steps.</p>
</li>
<li>
<p>Assign a small, dedicated CLI tool to each step.</p>
</li>
<li>
<p>Combine these tools, piping their outputs together, to solve the initial challenge.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer/crazy-terminal.gif" alt="crazy terminal">
</div>
</div>
<div class="paragraph">
<p>As a practical example, you want to select an arbitrary table from your
database, get all of the data within it, and pretty-print it as JSON.
You have two options:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Install and use a couple hundred megabytes of &#8220;pgAdmin&#8221; that
will create another distractive window in your workflow and eat your
memory, blasting your brain with all the buttons and menus around its
GUI.</p>
</li>
<li>
<p>Create a simple script that uses &#8220;psql&#8221; to get a list of all
tables in your database, pass them to &#8220;fzf&#8221; so you could interactively
select them, pass the table name again to &#8220;psql&#8221; to output data from it in
JSON, and finally pass it to &#8220;jq&#8221; to pretty-print the result.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Even though I have already intentionally hated on option 1, there could
be a point like: &#8220;Why would I do everything said in point 2 if I
can just go to pgAdmin and press a single button or two?&#8221;. And that is
valid. And here we come to one of the most important points: the
approach described in option 2 is just an example of a philosophy that you
can follow or <strong>not</strong>. And that is your choice. And it would not be
incorrect or make you a bad developer. It is all about what you prefer
(and how lazy you are :P). But if you selected option 2, then you
probably prioritize:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Modularity &amp; Portability</p>
</li>
<li>
<p>Better resource usage</p>
</li>
<li>
<p>Minimalistic &amp; distraction-free workflow</p>
</li>
<li>
<p>Scriptability &amp; Automation</p>
</li>
<li>
<p>Customisation</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Another interesting thing to think about the second approach is that if
you look closely, it is all about piping, or basically passing
data from one function to another. And with this approach, it gives you a
grounded look at something fundamental regarding software engineering in
general — it is quite a lot, if not completely, about viewing,
manipulating, and creating data. Actually, pretty much what our brains do.</p>
</div>
<div class="paragraph">
<p>Last but not least — such an approach really encourages learning,
deeper understanding, and mastering of general software engineering
skills, which eventually raises the level of craftsmanship. Personally,
this philosophy is what sparks joy in my everyday work.</p>
</div>
<div class="paragraph">
<p>Another philosophy that usually goes hand in hand with the terminal-first
one is mouseless or keyboard-centric development, which literally means
what it says — it encourages you to prioritize the usage of a keyboard
over a mouse or trackpad for writing or navigating through your code.
It is important to say here that it doesn’t mean that you should never use
those. Sometimes it is quite inefficient to avoid using your trackpad,
but for the most part, the theory is that mostly using your keyboard
makes your development faster, more efficient, and less tiring.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer/monkey-smashing-mouse.gif" alt="monkey smashing mouse">
</div>
</div>
<div class="paragraph">
<p>Why? Well, you keep your hands on the keyboard and avoid switching
between it and a mouse. Additionally, you rely on muscle memory in the
form of keybindings and not on visual navigation to perform actions.
This way you reduce mental overhead, stay in the flow state, and perform basic
actions much faster. For example,
<a href="https://blog.superhuman.com/keyboard-vs-mouse/?utm_source=chatgpt.com">the
research by SuperHuman</a> showed that some basic operations that we
perform every day can be done from 2 to 5 seconds faster if performed
with a keyboard rather than a mouse. And we perform those actions a lot, so
think about the amount of time you could save in a day.</p>
</div>
<div class="paragraph">
<p>But let&#8217;s not idealize things and talk about the downsides. The primary one is a steep learning curve.
From my experience, following those philosophies really makes you
rethink the way you approach software development. I struggle to point
out the exact points, but it just feels quite different, and you really
need time to get used to that new reality, and that basically means a
long learning curve. The basic parts of it are memorizing all the
keybinds or switching your mindset to use CLIs over graphical applications. But
hey, learning all the buttons in your IDE also took time, so it is more
about whether you are ready to commit to that.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_core_in_practice">Core In Practice</h2>
<div class="sectionbody">
<div class="paragraph">
<p>So now, let’s finally go from something totally metaphorical to something
more practical. There isn&#8217;t a single right way to implement the philosophy that
I described above. But, while finding my own way there, I could
distinguish two core elements or, in fact, pieces of software, that will
help you to build up a foundation.</p>
</div>
<div class="sect2">
<h3 id="_tmux">tmux</h3>
<div class="paragraph">
<p>I mentioned that with terminal-first development, your terminal
becomes the &#8220;central hub&#8221; for solving software engineering tasks.
When you think about a hub, you probably expect it to provide an infrastructure
that you can utilize to effectively achieve your goals.
The industry standard for that is called &#8220;tmux&#8221;,
which is a terminal multiplexer by its definition.</p>
</div>
<div class="paragraph">
<p>It allows you to conveniently create terminal windows, splits, or even
sessions for grouping. That makes it easy to organize your work between
multiple projects, for example, and allows you to navigate more smoothly.</p>
</div>
<div class="paragraph">
<p>You can say, “Yeah, but my terminal emulator can do the same.” Sure, but
what if the keybinds change? What if you switch to another emulator? What if
you now have to use a different system? You basically need to adapt and
configure this new tool for yourself. So how does using &#8220;tmux&#8221; help you?
It is completely platform and terminal-emulator agnostic. Everything you have
to do is to put your configuration file in the root folder and run &#8220;tmux&#8221;.
This way you are completely independent of the platform that you run &#8220;tmux&#8221; on top of.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer/tmux.png" alt="tmux">
</div>
</div>
<div class="paragraph">
<p>Another thing is that, at its core, &#8220;tmux&#8221; is a server, having all
your terminal sessions working in the background. So this can at least save
you from accidentally pressing Command + Q in your terminal and crashing
out again, but what you can also do is to basically have your whole
terminal session setup running, that you can SSH from any other machine
and have it all there, as &#8220;tmux&#8221; itself is just a command-line tool.
Combining a configuration basis and server nature, you basically become
independent of a machine and/or terminal emulation tools, if you have
your &#8220;tmux&#8221; server hosted somewhere.</p>
</div>
<div class="paragraph">
<p>Regarding the config, you can do quite a lot, starting from setting basic keybinds,
finishing with writing custom scripts for your workflow or modifying the UI.
There is even a whole ecosystem of plugins!</p>
</div>
<div class="paragraph">
<p>And if we talk about downsides, there are not that many, except
for the steep learning curve, but trust me, the outcome is worth it.</p>
</div>
</div>
<div class="sect2">
<h3 id="_neovim">neovim</h3>
<div class="paragraph">
<p>I think most of you know &#8220;vi&#8221; — the editor that&#8217;s impossible to exit. One of the
first text editors in existence, it relies on the keyboard only.
This is because there was no mouse in the early computer days. Theoretically, you can use
it to perform any tasks related to text editing and code writing. But
the problem with the original &#8220;vi&#8221; is that it is as plain as possible,
and when it comes to modern development, not really efficient. For
example, not having the ability to autocomplete code or quickly navigate to
a class definition doesn’t sound like a lot of productivity.</p>
</div>
<div class="paragraph">
<p>To solve this issue, &#8220;vim&#8221; was created — a feature-rich version of
the original &#8220;vi&#8221; with things like syntax highlighting, the ability to split
windows, etc. And most importantly — it provides the ability for extensive
configuration, even featuring its own language — &#8220;vimscript&#8221;. That
basically created the possibility to write plugins that allow you to
customize your experience in &#8220;vim&#8221; however you want. As a result,
the &#8220;vim&#8221; plugin ecosystem is probably one of the biggest plugin
ecosystems in the world.</p>
</div>
<div class="paragraph">
<p>But this was not enough for people who considered themselves to be ultra-hipsters.
This led to the creation of &#8220;Neovim&#8221; - a fork, partly rewritten in Lua.
This way, significant gains were achieved in terms of extensibility and architecture.
Nowadays, &#8220;Neovim&#8221; is known for its great documentation and is supported by a quite big and active community of contributors.</p>
</div>
<div class="paragraph">
<p>Ultimately, you can think of &#8220;*vim&#8221; as a constructor.
Its ecosystem provides you with the bricks you can use to build a development
tool to satisfy any of your needs. From the most plain text editor to
an ultra-feature-rich IDE. Basically, you can completely replace whatever you are using now.
Just watch out so as not to violate the Unix philosophy.</p>
</div>
<div class="paragraph">
<p>So how does switching to &#8220;*vim&#8221; feel, and what does it bring to your
life? First of all, text editing starts to feel so much smoother, and the
whole navigation process around the code feels really fluent. Using
&#8220;*vim&#8221; really proves the benefits of trusting your muscle memory via
keybinds instead of visual navigating. The overall overhead goes down,
and you can also feel it when you have to work with several
projects/directories. Opening a project, quickly looking for something,
and editing it feels so light and easy. Using &#8220;*vim&#8221; is like dropping
a huge backpack when going uphill and changing it for something small,
compact, accessible, but extendable at the same time. And last but not
least, making the editor behave literally however you want it to in
a programmatic way is another amazing part.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer/nvim.png" alt="nvim">
</div>
</div>
<div class="paragraph">
<p>But let’s not forget about the struggles you may face: &#8220;*vim&#8221; really makes
you rethink the way you write your code (and using keybinds is not the
only part), which will take quite some time. Another thing is
configuring the thing to meet your needs. Yeah, that takes time.
Initially, it took me maybe like 20+ hours, and it is also a non-stop
process, but that is a fair trade-off for the extensibility you get. There
is a joke in the &#8220;*vim&#8221; community about people spending more time on customizing
their config than on actually using it. And another thing is
that as it is community-driven, you may face things that don’t work
properly. For example, in order to have all the IDE features for Java,
you need to run Eclipse’s &#8220;jdtls&#8221;, a language server,
which doesn&#8217;t usually perform well on a large Java codebase.
But your mileage may vary.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusions">Conclusions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>My main point in this article was to provide you with a new perspective.
An approach that you can incorporate in your day-to-day tasks.
A philosophy that embraces you to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Think more about what your task involves and what you really need to solve it</p>
</li>
<li>
<p>Maintain your workspace clean and distraction-free</p>
</li>
<li>
<p>Build a unique environment that you love working in</p>
</li>
<li>
<p>Introduce joy and creativity into your routine</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>And while it might feel like a step back, this philosophy is surprisingly forward-thinking.
Many of today&#8217;s brand-new AI tools are designed specifically for the command line.
In the end, there is no single way to do things.
Technical benefits like efficiency are important, but so is finding joy and pride in your craft.
Hipster engineering is something that makes me a better professional and makes me love what I do.
My sincere hope is that you find your own way to do the same.
Thanks for reading.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-07-11-terminal-first-mouseless-development-or-how-to-be-hipster-engineer/dancing-puppy.gif" alt="dancing puppy">
</div>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Ctrl+Alt+Defeat: Noob vs. Neural Net</title>
		<link>https://blog.lunatech.com//posts/2025-07-04-ctrl-alt-defeat</link>
		
		<dc:creator><![CDATA[]]></dc:creator>
        <pubDate>2025-07-04T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[beyond-the-code]]></category>
                }
             {
            <category><![CDATA[bash-to-the-feature]]></category>
                }
             {
            <category><![CDATA[AI]]></category>
                }
             {
            <category><![CDATA[neural network]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-07-04-ctrl-alt-defeat</guid>

					<description>
                        <![CDATA[ For decades, competitive games have served as milestones in artificial intelligence research. From IBM’s Deep Blue beating Garry Kasparov at chess in 1997, to AlphaGo’s victory over Lee Sedol in 2016, games have offered a clear stage for AI to measure itself against the best human minds.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>For decades, competitive games have served as milestones in artificial intelligence research. From IBM’s Deep Blue beating Garry Kasparov at chess in 1997, to AlphaGo’s victory over Lee Sedol in 2016, games have offered a clear stage for AI to measure itself against the best human minds.</p>
</div>
<div class="paragraph">
<p>But as games have grown more complex, so too has the challenge. Turn-based board games like chess and Go, while difficult, offer complete information and relatively limited options per move. Real-time strategy games like StarCraft II and Dota 2, however, introduce chaos: thousands of actions per minute, imperfect information, shifting alliances, and the need for long-term planning — all in real time.</p>
</div>
<div class="paragraph">
<p>So the question arises: Can AI beat humans in these games, fairly, without relying on superhuman speed or godlike awareness? Let’s take a deeper look into how two landmark systems, OpenAI Five and AlphaStar, set out to do just that.<br></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_complexity_of_real_time_strategy_games">The Complexity of Real-Time Strategy Games</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To appreciate the achievements of AI in games like Dota 2 and StarCraft II, it&#8217;s essential to understand what makes these games hard:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Partial information: Players don’t see the whole map due to fog of war.<br></p>
</li>
<li>
<p>High action complexity: At any moment, there are thousands of possible moves.<br></p>
</li>
<li>
<p>Real-time dynamics: No turns, decisions must be made continuously.<br></p>
</li>
<li>
<p>Coordination: Especially in team games, success hinges on synergy and communication.<br></p>
</li>
<li>
<p>Long-term planning: Decisions made in the early game can determine the late-game outcome.<br></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Unlike games with set openings and established endgames, these environments are closer to the messiness of the real world and that’s exactly why they interest AI researchers.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_openai_five_dota_2_without_superpowers">OpenAI Five: Dota 2 Without Superpowers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In 2019, OpenAI introduced OpenAI Five, a team of five neural networks trained to play Dota 2, a popular and highly complex team-based multiplayer game. Unlike previous AIs, OpenAI Five didn’t rely on hardcoded rules. Instead, it learned by playing itself millions of times in a massive distributed training setup.</p>
</div>
<div class="paragraph">
<p>What made OpenAI Five especially impressive was the effort to simulate human-like constraints:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Reaction time was capped at 200 milliseconds, close to average human reflexes.<br></p>
</li>
<li>
<p>Actions per minute (APM) were restricted to human levels, avoiding the inhuman speed advantage.<br></p>
</li>
<li>
<p>It had no access to information unavailable to humans, like opponent positions under fog of war.<br></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Despite these constraints, OpenAI Five steadily improved and eventually beat top human teams culminating in a 2–0 victory over the reigning world champion team OG at The International in 2019.</p>
</div>
<div class="paragraph">
<p>Yet, Five was not without flaws. It was:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Weaker in novel situations it hadn’t seen during training.<br></p>
</li>
<li>
<p>Sometimes inflexible, making odd decisions when opponents deviated from expected tactics.<br></p>
</li>
<li>
<p>Emotionally agnostic, meaning while it would never play emotionally, it also doesn’t have the ability to read human psychology or use momentum the way humans do.<br></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Still, the fact that an AI could beat the world’s best without using non-human like reactions speeds speaks for itself.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_alphastar_outmaneuvering_pros_in_starcraft_ii">AlphaStar: Outmaneuvering Pros in StarCraft II</h2>
<div class="sectionbody">
<div class="paragraph">
<p>DeepMind’s AlphaStar tackled StarCraft II, another legendary RTS known for its brutal learning curve and mechanical demands. It used a combination of imitation learning (watching human games) and self-play reinforcement learning to master the game.</p>
</div>
<div class="paragraph">
<p>Like OpenAI Five, AlphaStar imposed human-like limitations:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Capped APM and reaction delays (averaging around 350 milliseconds).<br></p>
</li>
<li>
<p>Camera view limitations, meaning it had to "look" around the map like a human player.<br></p>
</li>
<li>
<p>Trained against a diversity of opponents and strategies.<br></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>AlphaStar climbed the European ladder to Grandmaster, ranking in the top 0.2% of players. It beat professional players like TLO and MaNa convincingly, sometimes using unexpected and creative strategies.</p>
</div>
<div class="paragraph">
<p>However, it too had its shortcomings:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Predictability: Once players had time to study it, some human pros found exploitable patterns.<br></p>
</li>
<li>
<p>Lack of intuitive game sense: Humans often make intuitive calls based on experience, psychology, or a “feel” for the flow of the game — AlphaStar relied solely on data and outcomes.<br></p>
</li>
<li>
<p>Difficulty adapting to “meta shifts”, since it lacked the kind of quick generalization humans can make from limited examples.<br></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Even so, AlphaStar showed that AI could compete — and win — not by outclicking, but by outthinking.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_summary_of_the_restrictions_imposed_on_the_ais">Summary of the restrictions imposed on the AI&#8217;s</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Metric</th>
<th class="tableblock halign-left valign-top">Pro Human Player</th>
<th class="tableblock halign-left valign-top">OpenAI Five</th>
<th class="tableblock halign-left valign-top">AlphaStar</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Average Reaction Time</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~200 ms</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">200 ms</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">350 ms</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Max APM</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~300</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~180</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~150</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Map Vision</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Partial</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Partial</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Limited camera view</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Strategy Adaptation</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">High</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Medium</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Medium-High</p></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect1">
<h2 id="_where_ai_still_falls_short">Where AI Still Falls Short</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Even with these victories, AI is not yet a complete replacement for human intelligence in games. Some weaknesses include:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Lack of common sense or intuition: AIs still struggle with decisions that require real-world reasoning or emotional awareness.<br></p>
</li>
<li>
<p>Context blindness: Without extensive training, AIs can’t generalize well to new game versions or unexpected strategies.<br></p>
</li>
<li>
<p>Communication and deception: While some advanced AIs, like Meta&#8217;s "CICERO", have made progress in games that involve negotiation and persuasion — such as the board game Diplomacy — most game-playing AIs still struggle to understand or influence human opponents the way skilled players can. They can&#8217;t read body language, sense bluffing, or adapt their strategy based on trust or psychology — key elements of human gameplay.<br></p>
</li>
<li>
<p>Creativity with purpose: AIs can discover new tactics, but they don’t “understand” them in a human sense, nor can they justify them conceptually.<br></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In essence, AI can win — but it doesn&#8217;t always know why it wins.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion_a_new_era_of_competitive_play">Conclusion: A New Era of Competitive Play</h2>
<div class="sectionbody">
<div class="paragraph">
<p>So, can AI truly outplay humans at complex games? The answer, remarkably, is yes — even under constraints that mimic human limitations. OpenAI Five and AlphaStar both demonstrated that intelligent agents can excel in games long thought too complex for machines.</p>
</div>
<div class="paragraph">
<p>But while the victories are real, the limitations are too. These AIs don’t think or feel like us. They win through scale, training, and narrow focus — not general intelligence or intuition.</p>
</div>
<div class="paragraph">
<p>Still, each success in these arenas nudges us closer to AI that can not only perform, but reason, adapt, and collaborate — skills that matter far beyond the game board.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>GPU Programming For The Brave</title>
		<link>https://blog.lunatech.com//posts/2025-06-27-gpu-programming-for-the-brave</link>
		
		<dc:creator><![CDATA[Boyuan Xiao]]></dc:creator>
        <pubDate>2025-06-27T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[beyond-the-code]]></category>
                }
             {
            <category><![CDATA[bash-to-the-feature]]></category>
                }
             {
            <category><![CDATA[GPU programming]]></category>
                }
             {
            <category><![CDATA[CUDA]]></category>
                }
             {
            <category><![CDATA[parallel programming]]></category>
                }
             {
            <category><![CDATA[AI]]></category>
                }
             {
            <category><![CDATA[neural network]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-06-27-gpu-programming-for-the-brave</guid>

					<description>
                        <![CDATA[ GPUs, some might call them graphic cards, have never been a stranger for video gamers. The evolution of GPUs significantly changed not just the video game industry, but also the field of parallel programming.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>GPUs, some might call them graphic cards, have never been a stranger for video gamers. The evolution of GPUs significantly changed not just the video game industry, but also the field of parallel programming.</p>
</div>
<div class="paragraph">
<p>I was lucky enough to participate some courses that briefly introduced GPU programming during my master study. As my first humble attempt, I hereby write down my knowledge and understanding about GPU programming in this blog post. Hopefully, after reading this write-up, you can have a basic idea about: how GPUs work, how to do some simple GPU programming and why it is so important to the field of AI.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_is_gpu">What is GPU</h2>
<div class="sectionbody">
<div class="paragraph">
<p>GPU is the abbreviation of "graphics processing unit". It is a specialized electronic circuit designed for digital image processing and to accelerate computer graphics, being present either as a discrete video card or embedded on motherboards, mobile phones, personal computers, workstations, and game consoles.</p>
</div>
<div class="paragraph">
<p>If you have tried to build your own PC, you will probably call the big gas-stove-look-a-like thing in <a href="#card">Figure 1</a> a GPU. However, this is not entirely correct. Graphics card is a more suitable name for it. And if you have ever had a chance to disassemble a graphics card like me, then I am sure you will notice there are much more than just a GPU on a graphics card. The GPU itself is only a small part on it and there&#8217;s memory, power supply and cooling unit. The composition resembles any normal PC you can see. <a href="#disassembled-card">Figure 2</a> is taken when I had an GPU memory overheating issue. As you can see in the picture, the GPU is surrounded by the red box and blue boxes for the GPU memory. The part on the right is the cooling unit.</p>
</div>
<div class="openblock float-group">
<div class="content">
<div id="card" class="imageblock left">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/my_graphics_card_2.png" alt="A" width="800">
</div>
<div class="title">Figure 1. My Nvidia RTX 3080.</div>
</div>
<div id="disassembled-card" class="imageblock right">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/my_graphics_card_1.png" alt="B" width="800">
</div>
<div class="title">Figure 2. My Nvidia RTX 3080 (disassemble).</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_small_exercise">The small exercise</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There is no way we can actually know how to do GPU programming by just looking at the composition picture. To help with the understanding, let&#8217;s consider a small code exercise where you have to implement a simple <code>fill_matrix</code> function in C to fill a rectangle shape within a two-dimensional matrix with some certain value:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-c" data-lang="c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

void fill_matrix(int **s, int x_len, int y_len, int draw_start, int draw_end, int value_to_fill) {
  // IMPLEMENT ME
}

void print_matrix(int **s, int x_len, int y_len) {
  // doesn't matter...
}

int64_t initialize_matrix(int rows, int cols) {
  // doesn't matter...
}

int main() {
  int **s = (int **)initialize_matrix(10, 10);
  printf("before: \n");
  print_matrix(s, 10, 10);

  fill_matrix(s, 10, 10, 2, 8 9);

  printf("after: \n");
  print_matrix(s, 10, 10);
  return 0;
}</code></pre>
</div>
</div>
<div class="sect2">
<h3 id="_c_version">C version</h3>
<div class="paragraph">
<p>Easy, isn&#8217;t it? All we need to do is to use two nested for-loops to fill the value when the loop arrives the expected range:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-c" data-lang="c">void fill_matrix(int **s, int x_len, int y_len, int draw_start, int draw_end, int value_to_fill) {
  for (int i = 0; i &lt; y_len; i++) {
    for (int j = 0; j &lt; x_len; j++) {
      if (i &gt; draw_start &amp;&amp; i &lt; draw_end &amp;&amp; j &gt; draw_start &amp;&amp; j &lt; draw_end) {
        s[i][j] = value_to_fill;
      }
    }
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you would like to speed up your implementation, you can even use <a href="https://www.openmp.org/">OpenMp</a> to turn your it into a multi-threaded implementation by simply adding <code>#pragma omp parallel for collapse(2)</code> on top of the outer for-loop. After re-compiling and running <code>export OMP_NUM_THREADS=4</code>, your program should automatically delegate the execution of the for-loop to at most 4 threads.</p>
</div>
<div class="paragraph">
<p>Now it seems like we really pushed to the boundary, and couldn&#8217;t get any more speedup unless increasing the number of threads. However, what we have seen so far is still in the realm of CPU programming, where your code gets executed by the CPU. Besides that, the time complexity of the implementation is <code>O(n*m)</code>, which is not a very pleasant number. So let&#8217;s try to make use of the power of GPUs, with which we could achieve O(1) complexity.</p>
</div>
</div>
<div class="sect2">
<h3 id="_cuda_version">CUDA version</h3>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>You might find it helpful to temporarily forget what you have learnt about <code>thread</code> and <code>kernel</code> when reading this section.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-c" data-lang="c">__global__ void fill_matrix_kernel(int* matrix, int rows, int cols, int draw_start, int draw_end, int value) {
    int row = blockIdx.y * blockDim.y + threadIdx.y;
    int col = blockIdx.x * blockDim.x + threadIdx.x;

    if (row &gt; draw_start &amp;&amp; row &lt; draw_end &amp;&amp; col &lt; draw_end &amp;&amp; col &gt; draw_start) {
        int idx = row * cols + col;
        matrix[idx] = value;
    }
}

int main() {
  const int rows = 10;
  const int cols = 10;
  const size_t size = rows * cols * sizeof(int);

  // Host memory
  int* h_matrix = (int *)malloc(size);

  // Device memory
  int* d_matrix;
  cudaMalloc((void **)&amp;d_matrix, size);

  // Define grid and block dimensions
  dim3 block(32, 32);  // 256 threads per block
  dim3 grid(
      (cols + block.x - 1) / block.x,  // ceil(cols/block.x)
      (rows + block.y - 1) / block.y   // ceil(rows/block.y)
  );

  // Launch kernel
  fill_matrix_kernel&lt;&lt;&lt;grid, block&gt;&gt;&gt;(d_matrix, rows, cols, 2, 8 9);

  // Copy result back to host
  cudaMemcpy(h_matrix, d_matrix, size, cudaMemcpyDeviceToHost);

  // Verify values
  print_matrix(h_matrix, rows, cols);

  // Cleanup
  free(h_matrix);
  cudaFree(d_matrix);

  return 0;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Above is the CUDA implementation. CUDA is a C-like programming language provided by Nvidia. Naturally, it only runs on Nvidia cards. To compile the code above, we can simply run <code>nvcc -o code_example code_example.cu</code> just like when compiling C code using <code>gcc</code>. Then, the <code>code_example</code> it produces also isn&#8217;t any different from other native executable, which could be run by the command <code>./code_example</code>.</p>
</div>
<div class="paragraph">
<p>So what happens when we run it? Besides allocating memory on the device, which is our graphics card, the computation kernel (the <code>fill_matrix_kernel</code> function) is executed by all the GPU threads that we requested simultaneously. In the example, we define a grid of one block ((10 + 32 - 1) / 32 = 1) with 256 threads on it. GPU threads are fundamentally different from the CPU threads we know. By design, the number of GPU threads on a GPU is much larger than the number of CPU threads on a CPU. On top of that, what is executed by CPU threads is completely dependent on how you program it. On contrast, GPU threads provides high-throughput due to the nature of simultaneous execution for a kernel. Therefore, we need a way to control the behavior of each GPU thread. Luckily, an unique <code>threadId</code> is assigned to each GPU thread within the same block and each block has a unique <code>blockId</code>. What we can do is to see if the the current thread is within the drawing range and fill the value accordingly based on the location of the thread (<code>blockId</code> * <code>number of blocks</code> + <code>threadId</code>) , which is exactly what the <code>if</code> clause is doing.</p>
</div>
<div class="openblock float-group">
<div class="content">
<div class="imageblock left">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/gpu_architecture_1.png" alt="A" width="480">
</div>
<div class="title">Figure 3. The Grid, The Block and The Thread.</div>
</div>
<div class="imageblock right">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/gpu_architecture_2.png" alt="B" width="800">
</div>
<div class="title">Figure 4. Nvidia&#8217;s interpretation.</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If we leave out the <code>main()</code> function, the actual implementation is only 6 lines and there is no loop being used at all. But how much faster it really is? When running with the matrix shape of 32768 * 32768, our CUDA implementation can finish it within 0.3 seconds while the C implementation needs 1.9 seconds.</p>
</div>
<div class="openblock float-group">
<div class="content">
<div class="imageblock text-center">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/speed_result.png" alt="Speed showcase." width="800">
</div>
<div class="title">Figure 5. Speed showcase.</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Impressive, isn&#8217;t it? But trust me, everything seems reasonable when you actually see the difference of thread numbers:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top"><a href="https://www.intel.com/content/www/us/en/products/sku/240782/intel-xeon-6966pc-processor-432m-cache-3-00-ghz/specifications.html">Intel® Xeon® 6966P-C Processor</a></th>
<th class="tableblock halign-left valign-top"><a href="https://www.amd.com/en/products/processors/workstations/ryzen-threadripper.html#specifications">AMD Ryzen Threadripper PRO 9995WX</a></th>
<th class="tableblock halign-left valign-top"><a href="https://www.nvidia.com/en-us/geforce/graphics-cards/50-series/rtx-5090/">Nvidia RTX 5090</a></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">192 threads in total</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">192 threads in total</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">21760 CUDA threads</p></td>
</tr>
</tbody>
</table>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>This code example might be too simple and too boring for you. But if you think of the matrix that we are filling as a screen, and the value as RGB value&#8201;&#8212;&#8201;We are actually rendering a screen!</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_okay_but_why_ai">Okay, but why AI?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As you might have heard, GPUs are widely used in the field of AI. Given the high-throughput trait of GPU, the process of AI model training can be significantly facilitated. But why is that?</p>
</div>
<div class="sect2">
<h3 id="_look_into_the_ai">Look into the AI</h3>
<div class="paragraph">
<p>Thankfully, Wikipedia made it a lot easier for me to explain AI:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>"The largest and most capable LLMs are generative pretrained transformers (GPTs), which are largely used in generative chatbots such as ChatGPT or Gemini."</pre>
</div>
</div>
<div class="literalblock">
<div class="content">
<pre>"A GPT is a type of LLM and a prominent framework for generative artificial intelligence. It is an artificial neural network that is used in natural language processing by machines.".</pre>
</div>
</div>
<div class="paragraph">
<p>To put it simply: <strong>most of the popular AIs are made of neural networks.</strong> A neural network is composite of multiple layers of nodes. The first layer takes input from the outside world, normally as the format of a vector of numbers. The output of a layer consists of the output number from each node, which is calculated by summing the input times the weight of the node (sum(input * weight)). And all the subsequent layers take input from the previous one. The process of training the neural network aims to find the weights for each nodes so that the output is most acceptable. And it requires to feed the input &#8594; calculate the output &#8594; compare with the expected output &#8594; adjust the weights repetitively.</p>
</div>
<div class="openblock float-group">
<div class="content">
<div class="imageblock text-center">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/neural_network.png" alt="Speed showcase." width="800">
</div>
<div class="title">Figure 6. A neural network.</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_we_can_let_gpu_run_this">We can let GPU run this</h3>
<div class="paragraph">
<p>If we try to write a simple implementation, or even pseudo code, of how things are done in each layer of a neural network, we could arrive at what is shown in <a href="#c-implementation">Figure 7</a>. Once again we see a pattern we have seen just before: a linear algebra calculation wrapped by two for-loops. Therefore, we can easily rewrite to a CUDA implementation shown in <a href="#cuda-implementation">Figure 8</a>.</p>
</div>
<div class="openblock float-group">
<div class="content">
<div id="c-implementation" class="imageblock left">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/neural_network_layer_c.png" alt="Speed showcase." width="600">
</div>
<div class="title">Figure 7. C implementation of a neural network layer.</div>
</div>
<div id="cuda-implementation" class="imageblock right">
<div class="content">
<img src="../media/2025-06-27-gpu-programming-for-the-brave/neural_network_layer_cuda.png" alt="Speed showcase." width="900">
</div>
<div class="title">Figure 8. CUDA implementation of a neural network layer.</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Both <a href="#c-implementation">Figure 7</a> and <a href="#cuda-implementation">Figure 8</a> are taken from a research article by Ricardo Brito et al[<a href="#1">[1]</a>]. The authors managed to utilize the high-throughput of GPU to accelerate the training process of a neural network in the year of 2016. Except for the countless open-source repositories that implement CUDA-based neural networks, Nvidia offers <a href="https://developer.nvidia.com/cudnn#">cuDNN</a> as a GPU-accelerated library of primitives for deep neural networks. Popular neural network frameworks like <a href="https://pytorch.org/get-started/locally/">PyTorch</a> and <a href="https://www.tensorflow.org/guide/gpu">TenhsorFlow</a> can operate on GPU devices without any extra effort.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_to_sum_up">To sum up</h2>
<div class="sectionbody">
<div class="paragraph">
<p>GPUs, which are originally made for graphics processing, has shown a huge potential in the field of parallel programming and AI training due to their high-throughput nature. This is achieved by piling significant amount of GPU threads and impose simultaneous execution of the compute kernel. Even though it&#8217;s not quite possible to assign GPU threads for different execution routine like CPU threads, we can still do minimum control-flow manipulation based on their <code>threadId</code>. Several examples of CUDA, which is a C-like GPU programming language offered by Nvidia, are also shown to demonstrate its syntax.</p>
</div>
<div class="paragraph">
<p>Finally, you can checkout the code examples I used in <a href="https://github.com/555isfaiz/gpu_programming_example">this GitHub repo</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_references">References</h2>
<div class="sectionbody">
<div class="ulist bibliography">
<ul class="bibliography">
<li>
<p>[[[1]]] Brito R., Fong S., Cho K., Song W., Wong R., Mohammed S., Fiaidhi J.
"GPU-enabled back-propagation artificial neural network for digit recognition in parallel".
<em>The Journal of Supercomputing</em>. 72, (2016).
<a href="https://doi.org/10.1007/s11227-016-1633-y" class="bare">https://doi.org/10.1007/s11227-016-1633-y</a></p>
</li>
</ul>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Graveyard of technologies</title>
		<link>https://blog.lunatech.com//posts/2025-06-20-graveyard-of-technologies</link>
		
		<dc:creator><![CDATA[Pere Tarrida]]></dc:creator>
        <pubDate>2025-06-20T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[beyond-the-code]]></category>
                }
             {
            <category><![CDATA[bash-to-the-feature]]></category>
                }
             {
            <category><![CDATA[ALGOL]]></category>
                }
             {
            <category><![CDATA[Japronto]]></category>
                }
             {
            <category><![CDATA[Apache Ant]]></category>
                }
             {
            <category><![CDATA[Windows Phone]]></category>
                }
             {
            <category><![CDATA[Google Glass]]></category>
                }
             {
            <category><![CDATA[Microsoft Zune]]></category>
                }
             {
            <category><![CDATA[Netscape Navigator]]></category>
                }
             {
            <category><![CDATA[Adobe Flash]]></category>
                }
             {
            <category><![CDATA[Visual Basic]]></category>
                }
             {
            <category><![CDATA[Fortran]]></category>
                }
             {
            <category><![CDATA[Smalltalk]]></category>
                }
             {
            <category><![CDATA[Technology Adoption]]></category>
                }
             {
            <category><![CDATA[Market Failure]]></category>
                }
             {
            <category><![CDATA[Software History]]></category>
                }
             {
            <category><![CDATA[Hardware History]]></category>
                }
             {
            <category><![CDATA[Ecosystem Strategy]]></category>
                }
             {
            <category><![CDATA[Innovation vs. Viability]]></category>
                }
             {
            <category><![CDATA[Legacy Technology]]></category>
                }
             {
            <category><![CDATA[Product Lifecycle]]></category>
                }
             {
            <category><![CDATA[Developer Experience]]></category>
                }
             {
            <category><![CDATA[User Adoption]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-06-20-graveyard-of-technologies</guid>

					<description>
                        <![CDATA[ ALGOL, Japronto, and Apache Ant represent fascinating case studies of software that, despite their technical merits, faced significant challenges in achieving lasting market success. Each offers valuable lessons about the complex relationship between technical excellence and commercial viability.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_software_when_technical_excellence_isnt_enough">Software: When Technical Excellence Isn&#8217;t Enough</h2>
<div class="sectionbody">
<div class="paragraph">
<p>ALGOL, Japronto, and Apache Ant represent fascinating case studies of software that, despite their technical merits, faced significant challenges in achieving lasting market success. Each offers valuable lessons about the complex relationship between technical excellence and commercial viability.
 ALGOL, Japronto, and Apache Ant: Lessons in Technology Adoption</p>
</div>
<div class="paragraph">
<p>Represent fascinating case studies of technologies that, despite their technical merits, faced significant challenges in achieving lasting market success. Each offers valuable lessons about the complex relationship between technical excellence and commercial viability.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_algol_revolutionary_syntax_that_shaped_programming">ALGOL: Revolutionary Syntax That Shaped Programming</h2>
<div class="sectionbody">
<div class="paragraph">
<p>ALGOL introduced groundbreaking programming concepts that influenced virtually every modern programming language. The language featured elegant recursive procedures and call-by-name parameters, as demonstrated in this classic example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-algol" data-lang="algol">real procedure GPS (I, N, Z, V); integer I; real N, Z, V;
begin
   for I := 1 step 1 until N do
      Z := V;
   GPS := 1;
end;</code></pre>
</div>
</div>
<div class="paragraph">
<p>This GPS (General Problem Solver) procedure showcased ALGOL&#8217;s sophisticated parameter passing mechanisms and recursive capabilities. The language&#8217;s clean syntax and mathematical precision made it ideal for academic research and algorithm description. ALGOL&#8217;s influence can be seen in modern languages through its introduction of block structure, lexical scoping, and formal syntax definition using Backus-Naur Form.</p>
</div>
<div class="paragraph">
<p>However, ALGOL&#8217;s academic origins became its commercial weakness. The language prioritized theoretical elegance over practical business applications, creating a barrier for commercial adoption. Unlike FORTRAN, which had IBM&#8217;s backing and clear scientific computing applications, ALGOL remained primarily an academic exercise without strong industry support.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_japronto_the_performance_paradox">Japronto: The Performance Paradox</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Japronto emerged as a high-performance Python HTTP framework, promising extraordinary speed through aggressive optimization. A typical Japronto application demonstrated its streamlined approach:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-python" data-lang="python">from japronto import Application

def hello(request):
    return request.Response(text='Hello world!')

app = Application()
app.router.add_route('/', hello)
app.run(debug=True)</code></pre>
</div>
</div>
<div class="paragraph">
<p>The framework achieved remarkable performance by optimizing HTTP pipelining and utilizing the picohttpparser C library with SSE4.2 CPU instructions. Japronto could handle over 1 million requests per second in benchmarks, dramatically outperforming traditional Python frameworks and even some Go alternatives.</p>
</div>
<div class="paragraph">
<p>However, this performance came at a significant cost. Japronto&#8217;s speed optimizations discouraged the use of Python-level objects and complex application logic. The framework relied heavily on HTTP pipelining, which modern browsers don&#8217;t support reliably. Most critically, real-world applications requiring database connections, business logic, and data processing couldn&#8217;t maintain Japronto&#8217;s benchmark performance levels.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_apache_ant_the_xml_build_tool_era">Apache Ant: The XML Build Tool Era</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Apache Ant dominated Java build automation for years with its XML-based configuration system. A typical Ant build file demonstrated its declarative approach:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;project name="MyFirstAntProject" default="compile" basedir="."&gt;
    &lt;property name="src.dir" location="src" /&gt;
    &lt;property name="build.dir" location="bin" /&gt;

    &lt;target name="clean"&gt;
        &lt;delete dir="${build.dir}" /&gt;
    &lt;/target&gt;

    &lt;target name="compile" depends="clean"&gt;
        &lt;javac srcdir="${src.dir}" destdir="${build.dir}" /&gt;
    &lt;/target&gt;
&lt;/project&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Ant succeeded in providing platform-independent build automation and flexible task execution. Its XML-based configuration allowed detailed control over build processes, and its extensible architecture supported custom tasks and complex build workflows.</p>
</div>
<div class="paragraph">
<p>However, Ant&#8217;s imperative approach became increasingly cumbersome as projects grew in complexity. The lack of dependency management, standardized project layouts, and convention-over-configuration principles made Ant builds verbose and difficult to maintain. Maven&#8217;s introduction of automatic dependency resolution and Gradle&#8217;s programmatic build scripts eventually displaced Ant in most modern Java projects.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_netscape_navigator_the_pioneer_that_lost_the_war">Netscape Navigator: The Pioneer That Lost the War</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Netscape Navigator pioneered web browsing and helped create the modern internet, but ultimately fell victim to Microsoft&#8217;s aggressive competitive tactics and strategic missteps. Despite its early dominance, Netscape&#8217;s market share collapsed in the late 1990s.</p>
</div>
<div class="paragraph">
<p>Netscape Navigator introduced fundamental web technologies including JavaScript, SSL encryption, and dynamic HTML capabilities. The browser&#8217;s plugin architecture and standards-based approach laid the foundation for modern web development and demonstrated the potential for rich, interactive web applications.</p>
</div>
<div class="paragraph">
<p>However, Netscape&#8217;s downfall illustrates how market leadership can quickly evaporate in fast-moving technology sectors. Microsoft leveraged its Windows monopoly to bundle Internet Explorer with every PC, making it the default browser for millions of users. Netscape also made strategic errors, including focusing too heavily on enterprise solutions while neglecting the consumer market, allowing Microsoft to catch up and eventually surpass Netscape&#8217;s technical capabilities.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_adobe_flash_actionscript_a_multimedia_giants_swift_decline">Adobe Flash + ActionScript: A Multimedia Giant&#8217;s Swift Decline</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For over a decade, Adobe Flash was the dominant platform for rich multimedia content on the web. Powered by ActionScript, a scripting language similar to JavaScript, Flash enabled highly interactive websites, games, and animations. A classic snippet of ActionScript might look like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-actionscript" data-lang="actionscript">var myText:TextField = new TextField();
myText.text = "Hello, World!";
myText.x = 100;
myText.y = 100;
addChild(myText);</code></pre>
</div>
</div>
<div class="paragraph">
<p>This interactivity revolutionized early web experiences, making Flash a staple in web development and advertising. ActionScript 3.0 introduced object-oriented features, bringing more structure and power to web applications.</p>
</div>
<div class="paragraph">
<p>Despite its popularity, Flash faced mounting criticism for its performance, security vulnerabilities, and closed ecosystem. The death knell came when Apple declined to support Flash on iOS, signaling the industry&#8217;s shift toward open standards like HTML5, CSS3, and JavaScript. Adobe officially ended Flash support in 2020.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_visual_basic_accessibility_meets_obsolescence">Visual Basic: Accessibility Meets Obsolescence</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Microsoft’s Visual Basic (VB) democratized Windows software development in the 1990s. Its simple syntax and drag-and-drop interface allowed non-programmers and beginners to create full-fledged Windows applications rapidly:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-vb" data-lang="vb">Module Module1
   Sub Main()
     Console.WriteLine("Hello World!")
   End Sub
End Module</code></pre>
</div>
</div>
<div class="paragraph">
<p>VB&#8217;s tight integration with the Windows API and rapid application development tools made it a hit for business applications. However, as .NET and more modern languages like C# emerged, Visual Basic was gradually phased out. VB.NET, its successor, attempted modernization but lacked traction among new developers.</p>
</div>
<div class="paragraph">
<p>The rise of more versatile, cross-platform, and open-source development frameworks ultimately made Visual Basic an outdated choice for contemporary software needs.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_fortran_the_long_reigning_king_of_scientific_computing">Fortran: The Long-Reigning King of Scientific Computing</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Developed in the 1950s, Fortran (FORmula TRANslation) was one of the first high-level programming languages. Its strength in numerical computation made it the go-to choice for scientists and engineers for decades. A basic Fortran program might look like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-fortran" data-lang="fortran">PROGRAM Hello
   PRINT *, 'Hello, world!'
END PROGRAM Hello</code></pre>
</div>
</div>
<div class="paragraph">
<p>Fortran introduced critical concepts like structured programming and efficient array handling, which made it ideal for high-performance computing tasks such as climate modeling and computational fluid dynamics.</p>
</div>
<div class="paragraph">
<p>Though still used in legacy scientific codebases, Fortran&#8217;s relevance has dwindled. Modern languages like Python, with libraries like NumPy and SciPy, offer more flexible and accessible alternatives, leading to Fortran’s slow fade from the mainstream.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_smalltalk_object_oriented_pioneer_with_limited_reach">Smalltalk: Object-Oriented Pioneer with Limited Reach</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Smalltalk was a trailblazer in object-oriented programming. It introduced core concepts such as message passing, live coding environments, and a uniform object model that inspired languages like Java, Python, and Ruby. A Smalltalk code example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-smalltalk" data-lang="smalltalk">Transcript show: 'Hello, world!'; cr.</code></pre>
</div>
</div>
<div class="paragraph">
<p>The entire environment was built from objects, offering unprecedented dynamism and introspection. Smalltalk&#8217;s interactive IDE and immediate feedback loop remain unmatched in some respects.</p>
</div>
<div class="paragraph">
<p>Yet, Smalltalk struggled with adoption due to performance issues, steep learning curves, and limited tooling outside its own ecosystem. While it remains influential in academic and niche circles, it was overshadowed by more pragmatic object-oriented languages that better integrated with mainstream operating systems and development workflows.</p>
</div>
</div>
</div>
<h1 id="_hardware_nightmares_when_innovation_meets_market_reality" class="sect0">Hardware Nightmares: When Innovation Meets Market Reality</h1>
<div class="paragraph">
<p>Windows Phone, Google Glass, Microsoft Zune, and Netscape Navigator represent fascinating case studies of hardware and platforms that, despite their technical innovations, faced significant challenges in achieving lasting market success. Each offers valuable lessons about the complex relationship between technological capability and commercial viability.</p>
</div>
<div class="sect1">
<h2 id="_windows_phone_microsofts_7_6_billion_lesson">Windows Phone: Microsoft&#8217;s $7.6 Billion Lesson</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Microsoft&#8217;s Windows Phone stands as one of tech&#8217;s most expensive failures, with the company writing off $7.6 billion related to the Nokia acquisition. Despite having superior hardware and a polished user interface, Windows Phone never gained meaningful market share.</p>
</div>
<div class="paragraph">
<p>The platform featured a unique tile-based interface that demonstrated Microsoft&#8217;s innovative approach to mobile design. This Live Tile system showcased Windows Phone&#8217;s dynamic interface capabilities and integration with the broader Windows ecosystem. The platform&#8217;s Metro design language influenced modern UI design principles and demonstrated Microsoft&#8217;s vision for unified experiences across devices.</p>
</div>
<div class="paragraph">
<p>However, Windows Phone&#8217;s failure stemmed from entering the market too late and creating a vicious ecosystem cycle. Microsoft launched Windows Phone 7 in 2010, three years after the iPhone had already transformed the industry. By then, iOS and Android had established dominant positions with hundreds of thousands of apps, while Windows Phone launched with only 2,000. The platform suffered from a destructive cycle where low user adoption meant developers ignored the platform, which in turn meant fewer apps, leading to even lower adoption.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_google_glass_the_wearable_that_wasnt_ready_for_society">Google Glass: The Wearable That Wasn&#8217;t Ready for Society</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Google Glass generated enormous hype as the future of wearable computing but crashed spectacularly due to privacy concerns and social acceptance issues. Despite Google&#8217;s technological prowess, the product was discontinued just two years after its 2013 launch.</p>
</div>
<div class="paragraph">
<p>The Glass platform introduced revolutionary concepts in augmented reality and hands-free computing. Its voice recognition capabilities and heads-up display technology influenced modern AR development and demonstrated the potential for seamless human-computer interaction through voice commands and gesture controls.</p>
</div>
<div class="paragraph">
<p>However, Google Glass faced a perfect storm of problems that made it unsuitable for mainstream adoption. The $1,500 price tag made it inaccessible to most consumers, while the device&#8217;s bulky design and visible camera created immediate privacy concerns. People worried about being recorded without consent, leading to bans in restaurants, bars, and other public spaces. Most critically, Google failed to clearly define the target market and value proposition for everyday users.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_microsoft_zune_the_ipod_killer_that_never_was">Microsoft Zune: The iPod Killer That Never Was</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Microsoft&#8217;s Zune music player launched in 2006 as a direct competitor to Apple&#8217;s iPod but failed to make a significant dent in Apple&#8217;s market dominance. Despite some innovative features, the Zune became synonymous with Microsoft&#8217;s inability to compete in consumer electronics.</p>
</div>
<div class="paragraph">
<p>Zune introduced innovative wireless sharing capabilities and social music discovery features that predated modern streaming services. Its larger screen and improved navigation demonstrated Microsoft&#8217;s understanding of user interface design, while the Zune software provided a more integrated media management experience than many competitors.</p>
</div>
<div class="paragraph">
<p>However, the Zune suffered from classic late-mover disadvantages. By 2006, the iPod had already established itself as the dominant music player, with a mature ecosystem including iTunes and strong brand loyalty. Microsoft&#8217;s device offered improvements like wireless sharing and a larger screen, but these incremental benefits weren&#8217;t enough to overcome Apple&#8217;s head start. Microsoft also struggled with marketing and brand positioning, lacking the sleek design aesthetic that made Apple products desirable.</p>
</div>
</div>
</div>
<h1 id="_conclusion_lessons_in_technology_adoption" class="sect0">Conclusion: Lessons in Technology Adoption</h1>
<div class="paragraph">
<p>The histories of these varied technologies illustrate a critical lesson: technical merit alone is insufficient to guarantee market success. Whether it&#8217;s a programming language like ALGOL that lacked commercial focus, a framework like Japronto whose benchmark performance was impractical for real-world use, or hardware like the Zune and Windows Phone that couldn&#8217;t overcome established ecosystems, the pattern is consistent.</p>
</div>
<div class="paragraph">
<p>Sustainable adoption requires a delicate balance of innovation with practical usability, strong industry support, and the ability to evolve alongside changing user needs and market dynamics. The failure to address real-world problems, build a supportive ecosystem, or adapt to new industry standards ultimately led to the decline of these once-promising technologies.</p>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>A brief introduction to HyperLogLog++</title>
		<link>https://blog.lunatech.com//posts/2025-06-13-hyperloglog</link>
		
		<dc:creator><![CDATA[Alberto]]></dc:creator>
        <pubDate>2025-06-13T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[hyperloglog]]></category>
                }
             {
            <category><![CDATA[algorithm]]></category>
                }
             {
            <category><![CDATA[randomized-algorithm]]></category>
                }
             {
            <category><![CDATA[beyond-the-code]]></category>
                }
             {
            <category><![CDATA[bash-to-the-feature]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-06-13-hyperloglog</guid>

					<description>
                        <![CDATA[ This document demonstrates a fascinating technique that tackles a complex computational problem using an elegant probabilistic strategy.]]></description>
                    <content:encoded><![CDATA[
                    <div id="toc" class="toc">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#introduction">The Problem</a></li>
<li><a href="#_the_algorithm">The Algorithm</a></li>
<li><a href="#_example">Example</a></li>
<li><a href="#_implementation">Implementation</a>
<ul class="sectlevel2">
<li><a href="#_data_structure">Data Structure</a></li>
<li><a href="#_add_operation">Add Operation</a></li>
<li><a href="#_count_operation">Count Operation</a></li>
<li><a href="#_merge_operation">Merge Operation</a></li>
</ul>
</li>
<li><a href="#_relative_percentage_error">Relative Percentage Error</a></li>
<li><a href="#_conclusion">Conclusion</a></li>
</ul>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This document demonstrates a fascinating technique that tackles a complex computational problem using an elegant probabilistic strategy.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="introduction">The Problem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <strong>count-distinct problem</strong> (also known as the <em>cardinality estimation problem</em>) involves finding the number of distinct elements in a data stream containing repeated elements.</p>
</div>
<div class="paragraph">
<p>Traditionally, solving this problem requires Θ(D) space complexity, where D represents the number of unique elements. This is because we need to store each unique element to determine whether a new element has been previously encountered.</p>
</div>
<div class="paragraph">
<p>Unfortunately, this approach doesn&#8217;t scale for massive cardinalities found in real-world applications such as:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Unique Query Counting</strong>: Tracking the number of unique searches in a search engine</p>
</li>
<li>
<p><strong>Network Monitoring</strong>: Counting unique source IP addresses</p>
</li>
<li>
<p><strong>Unique Visitor Tracking</strong>: Monitoring distinct users across web platforms</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
In the original paper and related literature, "cardinality" refers to the number of distinct elements.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_algorithm">The Algorithm</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When you only need an estimation, or when the number of unique elements makes it impractical to store them all in memory, <strong>HyperLogLog++</strong> provides an excellent solution.</p>
</div>
<div class="paragraph">
<p>This technique estimates the number of unique elements with a relative percentage error between -4% and 6%, using only 16 KB of memory (though this depends on the number of registers configured).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_example">Example</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Let me illustrate the core concept with a simple analogy.</p>
</div>
<div class="paragraph">
<p>Imagine someone spends an entire day rolling a die and tells you the maximum number of consecutive 1s they rolled was 3. While you can&#8217;t determine the exact number of rolls, you can estimate it by calculating the probability of this event occurring.</p>
</div>
<div class="paragraph">
<p>The probability of rolling three consecutive 1s is:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>1/6 * 1/6 * 1/6 = 1/(6^3)</pre>
</div>
</div>
<div class="paragraph">
<p>Therefore, the expected number of trials needed to observe this event is:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>1 / (1/6^3) = 6^3 = 216</pre>
</div>
</div>
<div class="paragraph">
<p>Translating this concept into an algorithm:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The <strong>Dice game</strong> becomes a Hash function that hashes the element in input and yields bits. These bits represent the outcome of the game run, like if the dice had only two faces, 1 and 0.</p>
</li>
<li>
<p>The event taken into account was that the longest sequence of 1&#8217;s (that the die returns 1) at the start of the game, but in this case, since hashing returns a binary output, the algorithm will calculate the event of longest run of leading bits set to 0. Technically, it&#8217;s also possible to count leading ones, but counting leading zeros is a common convention.</p>
</li>
<li>
<p><strong>Probability of rolling a 1 (1/6)</strong> → Probability of a bit being 0 (1/2)</p>
</li>
<li>
<p><strong>Number of plays</strong> → Cardinality</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This represents the fundamental idea behind the Flajolet–Martin algorithm, which HyperLogLog improves upon through three key enhancements.
*Correction Factor* is applied to mitigate the overestimation bias inherent in the standard HLL algorithm.
*Grouped Averaging* specifically the harmonic mean across multiple registers (or buckets), to significantly improve the accuracy of its cardinality estimates.
HLL for small cardinalities suffers from the Overestimation Bias, for that reason <strong>Linear Counting</strong> is used, which is another probabilistic counting algorithm simple and highly accurate for that scale.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_implementation">Implementation</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_data_structure">Data Structure</h3>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">class HyperLogLog {
    //Number of registers. Must be a power of 2. `buckets = 2^p`
    private final int buckets = 16384;

    // Correction factor
    private final double alpha = 0.7213 / (1 + 1.079 / buckets); //0.72125250052

    //Initialize the array of 16 383 (2^14-1) elements
    private final byte[] registers = new byte[buckets];</code></pre>
</div>
</div>
<div class="paragraph">
<p>The hash function outputs 64 bits, the first 14 are used to address the registers while the last 50 are used for calculating the ranking.
That&#8217;s why the size of the register array is <code>16384</code> and the type is <code>byte</code> sufficient to count up to 50 leading zeros.</p>
</div>
</div>
<div class="sect2">
<h3 id="_add_operation">Add Operation</h3>
<div class="paragraph">
<p>The <code>add</code> operation is how you feed individual elements into the HyperLogLog structure. The goal is to update the internal state of the HLL to reflect the presence of this new element.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">    public void add(String element) {
        // Calculate hash
        long hash = hashElement(element);
        // Take the first 14 bits to address the register
        short registerIndex = getIndex(hash);
        // Take the last 50 bits
        long value = getValue(hash);
        // Calculate the rank value for the target register
        byte rank = (byte) (leadingZeros(value) + 1);
        // Keep the biggest rank between rank and registers[registerIndex]
        if (rank &gt; registers[registerIndex]) {
            registers[registerIndex] = rank;
        }
    }</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Calculate</strong> a 64-bit hash of the input</p>
</li>
<li>
<p><strong>Extract</strong> the first 14 bits of the hash to index the register</p>
</li>
<li>
<p><strong>Use</strong> the remaining 50 bits to calculate the number of leading zeros</p>
</li>
<li>
<p><strong>Compare</strong> with the existing register value and store the biggest rank</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_count_operation">Count Operation</h3>
<div class="paragraph">
<p>The <code>count</code> operation provides an approximation of the number of distinct elements that have been added to the HyperLogLog.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">    public long count() {
        double sum = 0;
        int zeroRegisters = 0;
        // Calculate the harmonic mean of the register values
        for (byte register: registers) {
            sum += Math.pow(2, -register);
            if (register == 0) {
                zeroRegisters++;
            }
        }
        // Raw estimate
        double estimate = alpha * buckets * buckets / sum;
        // Apply corrections for small cardinalities
        if (estimate &lt;= 2.5 * m &amp;&amp; zeroRegisters &gt; 0) {
            // Linear counting
            estimate = buckets * Math.log((double) buckets / zeroRegisters);
        }
        return Math.round(estimate);
    }</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Calculate</strong> the harmonic mean of all register values</p>
</li>
<li>
<p><strong>Apply</strong> a correction factor</p>
</li>
<li>
<p><strong>Count</strong> the number of empty registers</p>
</li>
<li>
<p><strong>Fall back</strong> to linear counting for small cardinalities</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_merge_operation">Merge Operation</h3>
<div class="paragraph">
<p>The <code>merge</code> operation allows you to combine two or more HyperLogLog structures into a new HLL structure (or update one with another). This is a powerful feature for distributed systems where distinct counts might be computed on subsets of data in parallel and then combined.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">    public void merge(HyperLogLog that) {
        for (int i = 0; i &lt; buckets; i++) {
            if (this.registers[i] &lt; that.registers[i])
                this.registers[i] = that.registers[i];
        }
    }</code></pre>
</div>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Compare</strong> each register pair at the same index</p>
</li>
<li>
<p><strong>Retain</strong> the register with the larger value</p>
</li>
</ol>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_relative_percentage_error">Relative Percentage Error</h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="../media/2025-06-13-hyperloglog/error_plot.svg" alt="Error Plot">
</div>
</div>
<div class="paragraph">
<p>In this graph x-axis represents the expected cardinality, and it goes from 0 to 100k elements.
While the y-axis represents the relative error in percentage.
We can observe that in the first part that linear counting is used for cardinalities up to approximately 40,000, after which HyperLogLog++ takes over, the error is quite high, but it starts to converge around 0 the more elements come in.
The next graph shows what would happen without linear counting, the Overestimation Bias.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-06-13-hyperloglog/no_linear_counting.svg" alt="No Linear Counting">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>HyperLogLog++ is a good solution for counting unique elements in those use case where storing them in memory is not practical.
It provides O(1) complexity both in terms of time and space, and the relative error is in the range of -4% to 6%.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-06-13-hyperloglog/flajolet_philippe_small.jpg" alt="Philippe Flajolet">
</div>
</div>
<div class="paragraph">
<p><em>Philippe Flajolet - First author of "HyperLogLog: the analysis of a near-optimal
cardinality estimation algorithm"</em></p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>A Quest to Tame Large Language Models</title>
		<link>https://blog.lunatech.com//posts/2025-05-26-demystify-LLMs</link>
		
		<dc:creator><![CDATA[Luke Woodcock]]></dc:creator>
        <pubDate>2025-05-26T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[LLM]]></category>
                }
             {
            <category><![CDATA[natural language processing]]></category>
                }
             {
            <category><![CDATA[transformers]]></category>
                }
             {
            <category><![CDATA[machine learning]]></category>
                }
             {
            <category><![CDATA[AI]]></category>
                }
             {
            <category><![CDATA[language models]]></category>
                }
             {
            <category><![CDATA[probabilistic text generation]]></category>
                }
             {
            <category><![CDATA[statistical language models]]></category>
                }
             {
            <category><![CDATA[n-gram]]></category>
                }
             {
            <category><![CDATA[bigram]]></category>
                }
             {
            <category><![CDATA[attention mechanisms]]></category>
                }
             {
            <category><![CDATA[vector embeddings]]></category>
                }
             {
            <category><![CDATA[tokenization]]></category>
                }
             {
            <category><![CDATA[context windows]]></category>
                }
             {
            <category><![CDATA[self-attention]]></category>
                }
             {
            <category><![CDATA[neural networks]]></category>
                }
             {
            <category><![CDATA[NLP fundamentals]]></category>
                }
             {
            <category><![CDATA[AI architecture]]></category>
                }
             {
            <category><![CDATA[language understanding]]></category>
                }
             {
            <category><![CDATA[transformer architecture]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-05-26-demystify-LLMs</guid>

					<description>
                        <![CDATA[ Large Language Models represent one of the most significant advances in artificial intelligence, fundamentally transforming how we interact with natural language processing systems. Understanding their architecture and mechanisms is essential for anyone working with modern AI systems.]]></description>
                    <content:encoded><![CDATA[
                    <div id="toc" class="toc">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#introduction">Introduction</a></li>
<li><a href="#_1_the_foundation_probabilistic_text_generation">1. The Foundation: Probabilistic Text Generation</a>
<ul class="sectlevel2">
<li><a href="#_statistical_language_models">Statistical Language Models</a></li>
<li><a href="#_bi_gram_models">Bi-gram Models</a></li>
<li><a href="#_n_gram_models">N-gram Models</a></li>
</ul>
</li>
<li><a href="#_2_the_transformer_revolution_attention_is_all_you_need">2. The Transformer Revolution: "Attention is All You Need"</a>
<ul class="sectlevel2">
<li><a href="#_vector_representations">Vector Representations</a></li>
<li><a href="#_attention_mechanisms">Attention Mechanisms</a></li>
<li><a href="#_attention_architecture">Attention Architecture</a></li>
</ul>
</li>
<li><a href="#_technical_glossary">Technical Glossary</a>
<ul class="sectlevel2">
<li><a href="#_attention_mechanism">attention mechanism</a></li>
<li><a href="#_bigram_model">bigram model</a></li>
<li><a href="#_byte_pair_encoding">byte-pair encoding</a></li>
<li><a href="#_context">context</a></li>
<li><a href="#_corpus">corpus</a></li>
<li><a href="#_data_sparsity">data sparsity</a></li>
<li><a href="#_embedding">embedding</a></li>
<li><a href="#_epoch">epoch</a></li>
<li><a href="#_hyperparameter">hyperparameter</a></li>
<li><a href="#_long_range_dependencies">long range dependencies</a></li>
<li><a href="#_loss">loss</a></li>
<li><a href="#_n_gram_model">n-gram model</a></li>
<li><a href="#_over_fitting">over-fitting</a></li>
<li><a href="#_parameter">parameter</a></li>
<li><a href="#_parameter_space">parameter space</a></li>
<li><a href="#_preprocessing">preprocessing</a></li>
<li><a href="#_temperature">temperature</a></li>
<li><a href="#_token">token</a></li>
<li><a href="#_tokenization">tokenization</a></li>
<li><a href="#_training">training</a></li>
<li><a href="#_transformer">transformer</a></li>
<li><a href="#_vector">vector</a></li>
</ul>
</li>
</ul>
</div>
<div class="sect1">
<h2 id="introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Large Language Models represent one of the most significant advances in artificial intelligence, fundamentally transforming how we interact with natural language processing systems. Understanding their architecture and mechanisms is essential for anyone working with modern AI systems.</p>
</div>
<div class="paragraph">
<p>This guide examines the core concepts underlying LLMs, from foundational statistical models to sophisticated attention mechanisms, providing practical insights for implementation and deployment. We&#8217;ll explore how these systems generate coherent text, the role of context in language understanding, and the architectural innovations that enable modern capabilities.</p>
</div>
<div class="paragraph">
<p>If new to the language of LLMs, this guide aims to demystify some of the "magic" surrounding them. If already versed in the language of LLMs, this guide hopes to be a refresher.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_1_the_foundation_probabilistic_text_generation">1. The Foundation: Probabilistic Text Generation</h2>
<div class="sectionbody">
<div class="imageblock">
<div class="content">
<img src="../media/2025-05-26-demystify-LLMs/cotton-probability-machine-simple-compose.jpg" alt="Embroidered probability machine" width="900">
</div>
</div>
<div class="paragraph">
<p>Large Language Models operate as sophisticated probability machines. At their core, they analyze patterns in text data to predict the most likely next token given a specific context. While they incorporate stochastic elements through temperature controls, pedantically, their underlying mechanisms are fundamentally deterministic—the same prompt with identical parameters will consistently produce the same output. In pratice, however, they are far from determinisitic—the stochastic elements and numerous other caveats render that statement for "illustration purposes only".</p>
</div>
<div class="sect2">
<h3 id="_statistical_language_models">Statistical Language Models</h3>
<div class="paragraph">
<p>Statistical language models form the conceptual foundation for understanding modern LLMs. These models process a <a href="#_corpus">corpus</a> of text and use statistical patterns to predict subsequent words or <a href="#_tokenization">tokens</a>. While contemporary LLMs have evolved far beyond these simple approaches, understanding statistical models illuminates the core challenges that advanced architectures address.</p>
</div>
</div>
<div class="sect2">
<h3 id="_bi_gram_models">Bi-gram Models</h3>
<div class="paragraph">
<p>A <a href="#_bigram_model">bigram model</a> represents the simplest form of statistical language modeling. It analyzes pairs of consecutive words to build frequency tables that inform predictions.</p>
</div>
<div class="paragraph">
<p>Consider this example corpus:
<em>"The cat sat on the mat. The mat was soft and warm."</em></p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-05-26-demystify-LLMs/cat_on_warm_mat_simple_compose.jpg" alt="Embroidered cat on an embroidered mat" width="900">
</div>
</div>
<div class="paragraph">
<p>The resulting bi-gram frequency table would contain:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Bigram</th>
<th class="tableblock halign-left valign-top">Count</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">The cat</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">cat sat</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">sat on</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">on the</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">the mat</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">mat The</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">was soft</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">soft and</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">and warm</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>When processing the input "The," the model examines all bi-grams beginning with "The":</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"The cat" (1 occurrence)</p>
</li>
<li>
<p>"The mat" (2 occurrences)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The model predicts "mat" as the most probable next word based on frequency.</p>
</div>
<div class="paragraph">
<p>While effective for demonstration, <a href="#_bigram_model">bigram models</a> suffer from severe contextual limitations, because the consider only one preceding word for their predictions.</p>
</div>
</div>
<div class="sect2">
<h3 id="_n_gram_models">N-gram Models</h3>
<div class="paragraph">
<p>The <a href="#_n_gram_model">n-gram model</a> extends the bi-gram concept by incorporating longer <a href="#_context">contextual windows</a>. A trigram model, for example, considers two preceding words, while an n-gram model employs n-1 words of context.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s look at the sentence: <em>"Thank you very much for your cooperation. I very much appreciated it. We very much made progress."</em></p>
</div>
<div class="paragraph">
<p>A trigram model encountering "you very" would leverage both "you" and "very" to predict "much," using conditional probability <strong><em>P("much" | "you", "very")</em>.</strong></p>
</div>
<div class="paragraph">
<p>The relationship between context length and model performance involves critical trade-offs:</p>
</div>
<div class="paragraph">
<p><strong>Longer Context (Higher n):</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>Captures richer contextual dependencies</p>
</li>
<li>
<p>Enables more coherent text generation</p>
</li>
<li>
<p>Increases model complexity and <a href="#_parameter_space">parameter space</a></p>
</li>
<li>
<p>Higher risk of <a href="#_data_sparsity">data sparsity</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>Shorter Context (Lower n):</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>Simpler models with fewer parameters</p>
</li>
<li>
<p>More robust probability estimates</p>
</li>
<li>
<p>Limited contextual understanding</p>
</li>
<li>
<p>Reduced coherence in generated text</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><a href="#_data_sparsity">Data sparsity</a> becomes increasingly problematic as n increases—many <a href="#_n_gram_model">n-grams</a> may not appear frequently enough in training data to provide reliable probability estimates.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_2_the_transformer_revolution_attention_is_all_you_need">2. The Transformer Revolution: "Attention is All You Need"</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The transformer architecture, introduced by Google researchers, revolutionized natural language processing by solving the contextual limitations of <a href="#_n_gram_model">n-gram models</a> through sophisticated <a href="#_attention_mechanism">attention mechanisms</a>.</p>
</div>
<div class="sect2">
<h3 id="_vector_representations">Vector Representations</h3>
<div class="paragraph">
<p><a href="#_transformer">Transformers</a> convert words and <a href="#_token">tokens</a> into high-dimensional <a href="#_vector">vectors</a> (<a href="#_embedding">embeddings</a>) that capture semantic and syntactic relationships. Unlike sequential models that process text word-by-word, transformers can analyze relationships between all words in a passage simultaneously.</p>
</div>
<div class="paragraph">
<p><strong>Vector Dimensionality:</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>2D vectors contain 2 numbers (analogous to map coordinates)</p>
</li>
<li>
<p>3D vectors contain 3 numbers (spatial coordinates)</p>
</li>
<li>
<p>LLM vectors are high-dimensional with hundreds or thousands of dimensions</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Each dimension in an <a href="#_vector">vector</a> space captures different aspects of meaning, enabling the model to represent complex relationships between words and concepts. Vectors occupying similar positions in this space represent semantically related concepts.</p>
</div>
</div>
<div class="sect2">
<h3 id="_attention_mechanisms">Attention Mechanisms</h3>
<div class="paragraph">
<p>An <a href="#_attention_mechanism">attention mechanism</a> functions as a dynamic spotlight, highlighting relevant information during text processing. For each <a href="#_token">token</a>, the model calculates attention weights determining how much focus to allocate to every other token in the context.</p>
</div>
<div class="paragraph">
<p><strong>Key Advantages:</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Long-range Dependencies:</strong> Links related information across distant text portions</p>
</li>
<li>
<p><strong>Context-Aware Processing:</strong> Resolves ambiguous words based on surrounding context</p>
</li>
<li>
<p><strong>Parallel Processing:</strong> Analyzes all relationships simultaneously rather than sequentially</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_attention_architecture">Attention Architecture</h3>
<div class="paragraph">
<p><a href="#_attention_mechanism">Attention mechanisms</a> operate through three primary components for each <a href="#_token">token</a>:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Query Vector:</strong> Represents what the current token is "looking for"</p>
</li>
<li>
<p><strong>Key Vector:</strong> Represents what each token "offers" as context</p>
</li>
<li>
<p><strong>Value Vector:</strong> Contains the actual information to be combined</p>
</li>
</ol>
</div>
<div class="paragraph">
<p><strong>Processing Steps:</strong></p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Generate query, key, and value vectors for each token</p>
</li>
<li>
<p>Compare the current token&#8217;s query with all tokens' keys</p>
</li>
<li>
<p>Calculate attention scores indicating relevance strength</p>
</li>
<li>
<p>Use scores to weight value vectors</p>
</li>
<li>
<p>Combine weighted values to produce final token representation</p>
</li>
</ol>
</div>
<div class="paragraph">
<p><strong>Attention Weight Properties:</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>Higher weights indicate stronger relevance</p>
</li>
<li>
<p>Weights are normalized to form probability distributions (sum to 1)</p>
</li>
<li>
<p>Enable the model to focus on the most contextually relevant information</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>Self-Attention:</strong></p>
</div>
<div class="paragraph">
<p>Every token in a sequence attends to all others, including itself, capturing comprehensive contextual relationships across the entire sequence.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_technical_glossary">Technical Glossary</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_attention_mechanism">attention mechanism</h3>
<div class="paragraph">
<p>Mechanisms that enable models to weigh the importance of different input portions relative to each other, focusing on the most relevant information for accurate and coherent output generation.</p>
</div>
</div>
<div class="sect2">
<h3 id="_bigram_model">bigram model</h3>
<div class="paragraph">
<p>Statistical models that predict the next word based on the immediately preceding word, analyzing word pair frequencies to determine probability distributions.</p>
</div>
</div>
<div class="sect2">
<h3 id="_byte_pair_encoding">byte-pair encoding</h3>
<div class="paragraph">
<p>An algorithm for creating efficient tokenization by:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Counting character frequencies in the corpus</p>
</li>
<li>
<p>Identifying the most common character pairs</p>
</li>
<li>
<p>Adding common pairs to the vocabulary</p>
</li>
<li>
<p>Iteratively building tokens from frequent patterns</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_context">context</h3>
<div class="paragraph">
<p>The surrounding words or sequences that inform next-word prediction. Context length varies by model type—<a href="#_bigram_model">bigram models</a> use 1 word, trigram models use 2 words, and <a href="#_n_gram_model">ngram models</a> use n-1 words of context.</p>
</div>
</div>
<div class="sect2">
<h3 id="_corpus">corpus</h3>
<div class="paragraph">
<p>The comprehensive dataset of texts used for model training, typically including diverse sources such as books, articles, websites, and other written materials. Corpus quality and diversity directly impact model performance.</p>
</div>
</div>
<div class="sect2">
<h3 id="_data_sparsity">data sparsity</h3>
<div class="paragraph">
<p>Insufficient coverage of possible inputs or features in training data, where certain patterns may not appear frequently enough to provide reliable probability estimates.</p>
</div>
</div>
<div class="sect2">
<h3 id="_embedding">embedding</h3>
<div class="paragraph">
<p>Embeddings transform symbolic language into mathematical forms (the vector) that neural networks can process, with similar concepts positioned closer together in the vector space.</p>
</div>
<div class="paragraph">
<p>The terms "embedding" and "vector" are often used interchangeably in machine learning contexts, though "embedding" specifically speaks to the process of transforming data into the vector form, whereas "an embedding" likely speaks to a vector—unless a new model is invented that doesn&#8217;t use vectors.</p>
</div>
</div>
<div class="sect2">
<h3 id="_epoch">epoch</h3>
<div class="paragraph">
<p>One complete pass through the entire training dataset, during which the model processes all examples and updates parameters based on prediction errors.</p>
</div>
</div>
<div class="sect2">
<h3 id="_hyperparameter">hyperparameter</h3>
<div class="paragraph">
<p>A configuration setting that influences model behavior but is not learned during training. Examples include learning rate, batch size, and temperature. Hyperparameters are typically set before training begins and can significantly impact model performance.</p>
</div>
</div>
<div class="sect2">
<h3 id="_long_range_dependencies">long range dependencies</h3>
<div class="paragraph">
<p>Relationships between words or phrases separated by significant distances in text, such as pronouns referring to entities in different paragraphs.</p>
</div>
</div>
<div class="sect2">
<h3 id="_loss">loss</h3>
<div class="paragraph">
<p>A metric measuring prediction accuracy by quantifying the difference between model outputs and correct answers. Training progressively reduces loss through parameter optimization.</p>
</div>
</div>
<div class="sect2">
<h3 id="_n_gram_model">n-gram model</h3>
<div class="paragraph">
<p>Describes the general version of a bigram model. It is a statistical language modeling approach that predicts words based on n-1 previous words in sequence. Common variants include bigrams (n=2), trigrams (n=3).</p>
</div>
</div>
<div class="sect2">
<h3 id="_over_fitting">over-fitting</h3>
<div class="paragraph">
<p>A condition where models perform exceptionally on training data but fail to generalize to new, unseen inputs—analogous to memorizing without understanding.</p>
</div>
</div>
<div class="sect2">
<h3 id="_parameter">parameter</h3>
<div class="paragraph">
<p>The individual weights and biases within a model that are adjusted during training to minimize prediction error. Parameters are learned from the training data and define the model&#8217;s behavior.</p>
</div>
</div>
<div class="sect2">
<h3 id="_parameter_space">parameter space</h3>
<div class="paragraph">
<p>The multidimensional mathematical domain that encompasses all the weights and biases that the model can learn, which can number in the millions or billions for modern language models.</p>
</div>
</div>
<div class="sect2">
<h3 id="_preprocessing">preprocessing</h3>
<div class="paragraph">
<p>Data preparation steps including cleaning, transformation, and structuring to optimize datasets for machine learning, such as lowercasing text or removing stop words.</p>
</div>
</div>
<div class="sect2">
<h3 id="_temperature">temperature</h3>
<div class="paragraph">
<p>A hyperparameter controlling output randomness:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Lower Temperature:</strong> More deterministic, focused responses with higher probability words</p>
</li>
<li>
<p><strong>Higher Temperature:</strong> Increased randomness and creativity, selecting less probable words</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Not to be confused with the parameter space.</p>
</div>
</div>
<div class="sect2">
<h3 id="_token">token</h3>
<div class="paragraph">
<p>The fundamental unit of text processed by language models, representing a piece of text produced through tokenization. Tokens can be words, subwords, characters, or other linguistic units depending on the tokenization method used.</p>
</div>
</div>
<div class="sect2">
<h3 id="_tokenization">tokenization</h3>
<div class="paragraph">
<p>The process of segmenting text into smaller units (tokens) such as words, subwords, or characters. Effective tokenization increases training examples and enables models to learn morphological patterns.</p>
</div>
</div>
<div class="sect2">
<h3 id="_training">training</h3>
<div class="paragraph">
<p>The process of optimizing the model&#8217;s parameter space to maximize prediction accuracy, expressed as f(x|params) where x represents input and params represents learned weights.</p>
</div>
</div>
<div class="sect2">
<h3 id="_transformer">transformer</h3>
<div class="paragraph">
<p>A neural network architecture that consists of encoders (for understanding input) and decoders (for generating output), or decoder-only (for generative tasks). Transformers process all tokens in parallel rather than sequentially and better capture long range context.</p>
</div>
</div>
<div class="sect2">
<h3 id="_vector">vector</h3>
<div class="paragraph">
<p>High-dimensional numerical representations of text or data, capturing semantic and syntactic relationships in mathematical space suitable for computational processing.</p>
</div>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Part 4: Angular 19 Deep Dive – Smarter Forms with Signals and Control Flow</title>
		<link>https://blog.lunatech.com//posts/2025-05-20-part-4:-angular-19-deep-dive-–-smarter-forms-with-signals-and-control-flow</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-05-20T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[angular]]></category>
                }
             {
            <category><![CDATA[nestjs]]></category>
                }
             {
            <category><![CDATA[postgresql]]></category>
                }
             {
            <category><![CDATA[typeorm]]></category>
                }
             {
            <category><![CDATA[jwt]]></category>
                }
             {
            <category><![CDATA[authentication]]></category>
                }
             {
            <category><![CDATA[frontend]]></category>
                }
             {
            <category><![CDATA[typescript]]></category>
                }
             {
            <category><![CDATA[nodejs]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-05-20-part-4:-angular-19-deep-dive-–-smarter-forms-with-signals-and-control-flow</guid>

					<description>
                        <![CDATA[ Welcome back to the Full-Stack Authentication Boilerplate (Angular +]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome back to the Full-Stack Authentication Boilerplate (Angular<br>
NestJS + PostgreSQL) series. So far, we’ve wired up the backend and
built a working Angular frontend. Now it’s time to modernize our forms
using the latest Angular 19 features—specifically <strong>Signals</strong>, <strong>control
flow syntax</strong>, and <strong>defer blocks</strong>.</p>
</div>
<div class="paragraph">
<p>Angular 19 isn’t a total rewrite—it’s a refinement. It tightens up
template logic, improves reactivity, and lets us write cleaner, more
performant UI code. In this part, we’ll refactor the login and register
forms to take full advantage of these improvements.</p>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_angular_19_recap_and_what_actually_matters_for_devs">Angular 19 Recap (and What Actually Matters for Devs)</h3>
<div class="paragraph">
<p>Here’s what we’ll use in this part:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>✅ <strong>Signals</strong>: Angular’s native reactive primitive, lets you track
state like <code>useState()</code> in React—but fully integrated into Angular’s
change detection.</p>
</li>
<li>
<p>✅ <strong>Control Flow Syntax</strong> (<code>@if</code>, <code>@for</code>, <code>@switch</code>): Cleaner
alternatives to structural directives like <code>*ngIf</code> and <code>*ngFor</code>.</p>
</li>
<li>
<p>✅ <strong>Defer Blocks</strong>: Lazy-load parts of the UI, just like backend routes
or feature modules.</p>
</li>
<li>
<p>✅ <strong>@let Directive</strong>: Declare local variables directly in templates.</p>
</li>
<li>
<p>✅ <strong>Smarter Change Detection</strong>: Updates only the DOM parts that
actually changed, for faster UIs.</p>
</li>
</ul>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>For backend devs:</strong> Think of <code>signal()</code> like a reactive field or an
in-memory tracked variable; <code>@if</code>/<code>@for</code> in your templates is like
having expressive, inline logic with instant UI updates—no more verbose
boilerplate.</p>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_signals_or_reactive_forms">Signals or Reactive Forms?</h3>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>When to Use Each (for Backend Devs):</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Signals</strong> are perfect for local/component UI state and simple forms.</p>
</li>
<li>
<p><strong>Reactive Forms</strong> (<code>FormBuilder</code>, etc.) are the gold standard for
complex, validation-heavy, or dynamic forms—especially if you need
granular error handling or will scale up forms later.</p>
</li>
<li>
<p><strong>Pro Tip:</strong> You can use both! Track form state with Reactive Forms,
then reflect with signals using Angular’s <code>toSignal()</code> utility for the
best DX.</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">// Example: Bridge form values to signals
formValue = toSignal(form.valueChanges, { initialValue: form.value });</code></pre>
</div>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_migration_ngmodules_standalone_components">Migration: NgModules → Standalone Components</h3>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>Old way:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">@NgModule({
  declarations: [LoginComponent],
  imports: [ReactiveFormsModule],
})
export class AuthModule {}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>New way (Angular 15+):</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">@Component({
  standalone: true,
  selector: 'app-login',
  templateUrl: './login.component.html',
  imports: [ReactiveFormsModule],
})
export class LoginComponent {}</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>No more <code>@NgModule</code> needed.</p>
</li>
<li>
<p>Use <code>standalone: true</code> and import dependencies directly in the
component.</p>
</li>
<li>
<p>Both patterns can coexist during migration.</p>
</li>
</ul>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_refactoring_the_login_form">Refactoring the Login Form</h3>
<div class="paragraph">
<p>Here’s how to use Reactive Forms as the foundation, enhanced with
signals and modern control flow blocks.</p>
</div>
<div class="sect3">
<h4 id="_login_component_ts"><code>login.component.ts</code></h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import {
  Component,
  computed,
  signal,
  inject,
  ChangeDetectionStrategy,
} from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { toSignal } from '@angular/core/rxjs-interop';
import { take } from 'rxjs/operators';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss'],
  standalone: true,
  imports: [ReactiveFormsModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoginComponent {
  private readonly fb = inject(FormBuilder);
  readonly form = this.fb.group({
    email: ['', [Validators.required, Validators.email]],
    password: ['', [Validators.required, Validators.minLength(6)]],
  });

  readonly isLoading = signal(false);
  readonly errorMessage = signal&lt;string | null&gt;(null);

  readonly formValue = toSignal(this.form.valueChanges, {
    initialValue: this.form.value,
  });
  readonly formStatus = toSignal(this.form.statusChanges, {
    initialValue: this.form.status,
  });
  readonly isFormValid = computed(() =&gt; this.formStatus() === 'VALID');

  constructor(
    private readonly auth: AuthService,
    private readonly router: Router
  ) {}

  onSubmit() {
    if (!this.isFormValid()) return;

    const { email, password } = this.form.getRawValue();
    if (!email || !password) return;

    this.isLoading.set(true);
    this.errorMessage.set(null);

    this.auth
      .login({ email, password })
      .pipe(take(1))
      .subscribe({
        next: () =&gt; {
          this.isLoading.set(false);
          this.router.navigate(['/welcome']);
        },
        error: (err) =&gt; {
          this.isLoading.set(false);
          const message =
            err?.error?.message ||
            err?.message ||
            'Login failed. Please try again.';
          this.errorMessage.set(message);
        },
      });
  }
}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect3">
<h4 id="_migration_control_flow_syntax">Migration: Control Flow Syntax</h4>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>Before (classic Angular):</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;div *ngIf="loading"&gt;Loading...&lt;/div&gt;
&lt;ul&gt;
  &lt;li *ngFor="let user of users"&gt;{{ user.name }}&lt;/li&gt;
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>After (Angular 17+):</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@if (loading) {
  &lt;div&gt;Loading...&lt;/div&gt;
}
&lt;ul&gt;
  @for (user of users) {
    &lt;li&gt;{{ user.name }}&lt;/li&gt;
  }
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>The new syntax is cleaner and more readable.</p>
</li>
<li>
<p>You can use both during your migration to Angular 17+.</p>
</li>
</ul>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect3">
<h4 id="_login_component_html"><code>login.component.html</code></h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;form
  [formGroup]="form"
  (ngSubmit)="onSubmit()"
  class="mt-4 p-4 border rounded shadow-sm bg-white"
  style="max-width: 400px; margin: auto"
&gt;
  &lt;h2 class="text-center mb-4"&gt;Login&lt;/h2&gt;

  &lt;div class="mb-3"&gt;
    @let isInvalidEmail = form.get('email')?.invalid &amp;&amp; form.get('email')?.touched;
    &lt;input
      formControlName="email"
      type="email"
      class="form-control"
      placeholder="Email"
      [class.is-invalid]="isInvalidEmail"
      aria-label="Email"
    /&gt;
    @if (isInvalidEmail) {
      &lt;div class="invalid-feedback"&gt;Please enter a valid email.&lt;/div&gt;
    }
  &lt;/div&gt;

  &lt;div class="mb-3"&gt;
    @let isInvalidPassword = form.get('password')?.invalid &amp;&amp; form.get('password')?.touched;
    &lt;input
      formControlName="password"
      type="password"
      class="form-control"
      placeholder="Password"
      [class.is-invalid]="isInvalidPassword"
      aria-label="Password"
    /&gt;
    @if (isInvalidPassword) {
      &lt;div class="invalid-feedback"&gt;
        Password must be at least 6 characters long.
      &lt;/div&gt;
    }
  &lt;/div&gt;

  @if (errorMessage()) {
    &lt;div class="alert alert-danger"&gt;{{ errorMessage() }}&lt;/div&gt;
  }

  &lt;button
    type="submit"
    class="btn btn-primary w-100"
    [disabled]="isLoading() || !isFormValid()"
  &gt;
    @if (isLoading()) {
      &lt;span class="spinner-border spinner-border-sm me-2"&gt;&lt;/span&gt;
    }
    Login
  &lt;/button&gt;
&lt;/form&gt;</code></pre>
</div>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_refactoring_the_register_form">Refactoring the Register Form</h3>
<div class="sect3">
<h4 id="_register_component_ts"><code>register.component.ts</code></h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import {
  Component,
  computed,
  signal,
  inject,
  ChangeDetectionStrategy,
} from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { toSignal } from '@angular/core/rxjs-interop';
import { take } from 'rxjs/operators';

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.scss'],
  standalone: true,
  imports: [ReactiveFormsModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RegisterComponent {
  private readonly fb = inject(FormBuilder);
  readonly form = this.fb.group({
    name: ['', [Validators.required]],
    email: ['', [Validators.required, Validators.email]],
    password: ['', [Validators.required, Validators.minLength(6)]],
    role: ['user', [Validators.required]],
  });

  readonly isLoading = signal(false);
  readonly errorMessage = signal&lt;string | null&gt;(null);

  readonly formValue = toSignal(this.form.valueChanges, {
    initialValue: this.form.value,
  });
  readonly formStatus = toSignal(this.form.statusChanges, {
    initialValue: this.form.status,
  });
  readonly isFormValid = computed(() =&gt; this.formStatus() === 'VALID');

  constructor(
    private readonly auth: AuthService,
    private readonly router: Router
  ) {}

  onSubmit() {
    if (!this.isFormValid()) return;

    const { name, email, password, role } = this.form.getRawValue();
    if (!name || !email || !password || !role) return;

    this.isLoading.set(true);
    this.errorMessage.set(null);

    this.auth
      .register({ name, email, password, role })
      .pipe(take(1))
      .subscribe({
        next: () =&gt; {
          this.isLoading.set(false);
          this.router.navigate(['/login']);
        },
        error: (err) =&gt; {
          this.isLoading.set(false);
          const message =
            err?.error?.message ||
            err?.message ||
            'Registration failed. Please try again.';
          this.errorMessage.set(message);
        },
      });
  }
}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect3">
<h4 id="_register_component_html"><code>register.component.html</code></h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;form
  [formGroup]="form"
  (ngSubmit)="onSubmit()"
  class="mt-4 p-4 border rounded shadow-sm bg-white"
  style="max-width: 400px; margin: auto"
&gt;
  &lt;h2 class="text-center mb-4"&gt;Register&lt;/h2&gt;

  &lt;div class="mb-3"&gt;
    @let isInvalidName = form.get('name')?.invalid &amp;&amp; form.get('name')?.touched;
    &lt;input
      formControlName="name"
      type="text"
      class="form-control"
      placeholder="Name"
      [class.is-invalid]="isInvalidName"
      aria-label="Name"
    /&gt;
    @if (isInvalidName) {
      &lt;div class="invalid-feedback"&gt;Name is required.&lt;/div&gt;
    }
  &lt;/div&gt;

  &lt;div class="mb-3"&gt;
    @let isInvalidEmail = form.get('email')?.invalid &amp;&amp; form.get('email')?.touched;
    &lt;input
      formControlName="email"
      type="email"
      class="form-control"
      placeholder="Email"
      [class.is-invalid]="isInvalidEmail"
      aria-label="Email"
    /&gt;
    @if (isInvalidEmail) {
      &lt;div class="invalid-feedback"&gt;Please enter a valid email.&lt;/div&gt;
    }
  &lt;/div&gt;

  &lt;div class="mb-3"&gt;
    @let isInvalidPassword = form.get('password')?.invalid &amp;&amp; form.get('password')?.touched;
    &lt;input
      formControlName="password"
      type="password"
      class="form-control"
      placeholder="Password"
      [class.is-invalid]="isInvalidPassword"
      aria-label="Password"
    /&gt;
    @if (isInvalidPassword) {
      &lt;div class="invalid-feedback"&gt;
        Password must be at least 6 characters long.
      &lt;/div&gt;
    }
  &lt;/div&gt;

  @if (errorMessage()) {
    &lt;div class="alert alert-danger"&gt;{{ errorMessage() }}&lt;/div&gt;
  }

  &lt;button
    type="submit"
    class="btn btn-success w-100"
    [disabled]="isLoading() || !isFormValid()"
  &gt;
    @if (isLoading()) {
      &lt;span class="spinner-border spinner-border-sm me-2"&gt;&lt;/span&gt;
    }
    Register
  &lt;/button&gt;
&lt;/form&gt;</code></pre>
</div>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_real_world_patterns_for_backend_devs">Real-World Patterns for Backend Devs</h3>
<div class="sect3">
<h4 id="_signals_vs_observables">✅ Signals vs Observables</h4>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>Rule of Thumb:</strong> Use signals for local, component-level UI state. Use
observables for async or backend-driven data.</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p><strong>Signals (local state):</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">isModalOpen = signal(false);

openModal() { this.isModalOpen.set(true); }
closeModal() { this.isModalOpen.set(false); }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@if (isModalOpen()) {
  &lt;app-modal (close)="closeModal()"&gt;&lt;/app-modal&gt;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Observables (async state):</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">private modalSubject = new BehaviorSubject(false);
isModalOpen$ = this.modalSubject.asObservable();

openModal() { this.modalSubject.next(true); }
closeModal() { this.modalSubject.next(false); }</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@let isOpen = (isModalOpen$ | async);
@if (isOpen) {
  &lt;app-modal (close)="closeModal()"&gt;&lt;/app-modal&gt;
}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect3">
<h4 id="_control_flow_in_action">✅ Control Flow in Action</h4>
<div class="paragraph">
<p><strong>Using <code>@for</code> instead of <code>*ngFor</code>:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;ul&gt;
  @for (user of users; track user.id) {
    &lt;li&gt;{{ user.name }}&lt;/li&gt;
  }
&lt;/ul&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Using <code>@switch</code> vs <code>*ngSwitch</code>:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@switch (status) {
  @case ('loading') {
    &lt;p&gt;Loading...&lt;/p&gt;
  } @case ('error') {
    &lt;p&gt;Error!&lt;/p&gt;
  } @default {
    &lt;p&gt;All good.&lt;/p&gt;
  }
}</code></pre>
</div>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>Backend parallel:</strong> <code>@if</code>, <code>@for</code>, and <code>@switch</code> are like inline logic
in your backend template engines (e.g., EJS, Razor, Thymeleaf)—but here
they’re fully reactive and type-safe.</p>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect3">
<h4 id="_lazy_loading_and_ux_patterns_with_defer">✅ Lazy Loading and UX Patterns with @defer</h4>
<div class="paragraph">
<p>Angular’s <code>@defer</code> block is great for loading UI only when needed.</p>
</div>
<div class="paragraph">
<p><strong>Basic Usage:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@defer (when isHeavyComponentVisible) {
  &lt;app-heavy-widget&gt;&lt;/app-heavy-widget&gt;
} @placeholder {
  &lt;p&gt;Loading widget...&lt;/p&gt;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Loading feedback:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@defer (when dataReady; loading minimum 300ms) {
  &lt;app-dashboard&gt;&lt;/app-dashboard&gt;
} @loading {
  &lt;p&gt;Loading dashboard...&lt;/p&gt;
} @placeholder {
  &lt;p&gt;Initializing view...&lt;/p&gt;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Viewport entry:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@defer (on viewport) {
  &lt;app-news-feed&gt;&lt;/app-news-feed&gt;
} @placeholder {
  &lt;p&gt;Loading news feed when visible...&lt;/p&gt;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Idle trigger:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">@defer (on idle) {
  &lt;app-recommendations&gt;&lt;/app-recommendations&gt;
}</code></pre>
</div>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>⏳ <strong>Why care?</strong> Optimizes TTI (time to interactive) on heavy or mobile
pages.</p>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect3">
<h4 id="_smart_change_detection_in_a_dashboard">✅ Smart Change Detection in a Dashboard</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">userCount = signal(0);
orderTotal = signal(0);

ngOnInit() {
  this.api.getUsers().subscribe(users =&gt; this.userCount.set(users.length));
  this.api.getOrders().subscribe(orders =&gt; this.orderTotal.set(orders.length));
}</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;div&gt;Users: {{ userCount() }}&lt;/div&gt;
&lt;div&gt;Orders: {{ orderTotal() }}&lt;/div&gt;</code></pre>
</div>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p><strong>Signals update just what changed—no wasted DOM re-renders.</strong></p>
</div>
</blockquote>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_ssr_hydration_bonus_note">SSR &amp; Hydration (Bonus Note)</h3>
<div class="paragraph">
<p>💡 <em>SSR &amp; Hydration</em>: Angular 19’s hydration improvements are especially
useful if you’re rendering Angular on the server (Angular Universal).
Most projects won’t need this—but it’s a great step for future-proofing.</p>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_final_thoughts">Final Thoughts</h3>
<div class="paragraph">
<p>Angular 19 brings a more approachable and modern developer experience: signals simplify state, <code>@if</code> and <code>@for</code> make templates more readable, and <code>@defer</code> gives you fine control over performance.</p>
</div>
<div class="paragraph">
<p><strong>You just:</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>Replaced legacy form logic with clean Signals-based state.</p>
</li>
<li>
<p>Simplified templates using Angular’s new control flow.</p>
</li>
<li>
<p>Learned how to delay rendering and optimize performance with <code>@defer</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>Next:</strong> We’ll bring everything together in Part 5 with route guards,
token parsing, and role-based access control.</p>
</div>
<hr>
<div class="sect3">
<h4 id="_further_reading">Further Reading</h4>
<div class="ulist">
<ul>
<li>
<p><a href="https://angular.dev">Angular 19 Signals Guide (angular.dev)</a></p>
</li>
<li>
<p><a href="https://angular.dev/reference/forms/using-signals">Reactive Forms
vs. Signals—How to Choose</a></p>
</li>
</ul>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Part 3: Frontend Setup with Angular</title>
		<link>https://blog.lunatech.com//posts/2025-05-06-part-3%3A-frontend-setup-with-angular</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-05-06T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[angular]]></category>
                }
             {
            <category><![CDATA[nestjs]]></category>
                }
             {
            <category><![CDATA[postgresql]]></category>
                }
             {
            <category><![CDATA[typeorm]]></category>
                }
             {
            <category><![CDATA[jwt]]></category>
                }
             {
            <category><![CDATA[authentication]]></category>
                }
             {
            <category><![CDATA[frontend]]></category>
                }
             {
            <category><![CDATA[typescript]]></category>
                }
             {
            <category><![CDATA[nodejs]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-05-06-part-3%3A-frontend-setup-with-angular</guid>

					<description>
                        <![CDATA[ Now that we’ve built our NestJS backend with secure JWT auth, it’s time]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Now that we’ve built our NestJS backend with secure JWT auth, it’s time
to wire up the frontend. In this part, we’ll scaffold an <strong>Angular</strong> app,
integrate it with our backend, and secure it with <strong>JWT-based route
protection</strong>.</p>
</div>
<div class="paragraph">
<p>By the end of this part, you’ll have:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A basic Angular app styled with Bootstrap</p>
</li>
<li>
<p>Auth service for login/register with JWT handling</p>
</li>
<li>
<p>Login and Register components using reactive forms</p>
</li>
<li>
<p>A protected Welcome page</p>
</li>
<li>
<p>Route guard to lock down private views</p>
</li>
</ul>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_step_1_initialize_the_angular_frontend"><strong>Step 1: Initialize the Angular Frontend</strong></h3>
<div class="paragraph">
<p>Let’s get your frontend up and running. Open your terminal and run:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">ng new frontend
cd frontend</code></pre>
</div>
</div>
<div class="paragraph">
<p>Pick SCSS (or your favorite style option) when prompted.<br>
This gives you a fresh Angular workspace to play with.</p>
</div>
<div class="sect3">
<h4 id="_what_is_ng_in_angular_cli">What is <code>ng</code> in Angular CLI?</h4>
<div class="paragraph">
<p>The <code>ng</code> command is the core of the Angular CLI (Command Line Interface)
— a powerful toolkit that streamlines Angular development from start to
finish. It acts as a shortcut to perform a wide range of tasks without
manually setting up files or configurations.</p>
</div>
<div class="paragraph">
<p>With <code>ng</code>, you can quickly scaffold new projects, generate application
features, and manage your build and development workflow with ease. Here
are some common <code>ng</code> commands and what they do:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>ng new</code>: Creates a new Angular project with a complete directory
structure, TypeScript configuration, and ready-to-run setup.</p>
</li>
<li>
<p><code>ng generate</code> (or <code>ng g</code>): Automatically creates Angular building
blocks such as components, services, directives, pipes, and more —
following Angular’s style guide and best practices.</p>
</li>
<li>
<p><code>ng serve</code>: Launches a local development server with live reload. As
you make changes, the app updates instantly in the browser.</p>
</li>
<li>
<p><code>ng build</code>: Compiles your application into optimized static files for
production deployment.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The real power of <code>ng</code> lies in automation. It eliminates repetitive
boilerplate and helps you stick to Angular conventions, leading to
cleaner, more maintainable codebases.</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>💡 <strong>Tip:</strong> With Angular v19, components and services are created as
<strong>standalone</strong> by default. This means they no longer need to be declared
in NgModules, which promotes better modularity and reduces coupling in
your app architecture.</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p>By mastering the <code>ng</code> CLI, you’re not just saving time — you’re building
apps the Angular way, with a foundation rooted in scalability and
consistency.</p>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_step_2_install_dependencies"><strong>Step 2: Install Dependencies</strong></h3>
<div class="paragraph">
<p>We’ll need a few extras to make our app functional and visually
appealing:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Bootstrap</strong>: For responsive and professional styling.</p>
</li>
<li>
<p><strong>jwt-decode</strong>: To decode JWTs and extract user information.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Install them with:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm install bootstrap jwt-decode</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_3_set_up_bootstrap"><strong>Step 3: Set Up Bootstrap</strong></h3>
<div class="paragraph">
<p>Let’s make things look good with minimal effort.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Open <code>angular.json</code></p>
</li>
<li>
<p>Find the <code>"styles"</code> array and add Bootstrap’s CSS:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">"styles": [
  "node_modules/bootstrap/dist/css/bootstrap.min.css",
  "src/styles.scss"
]</code></pre>
</div>
</div>
</li>
<li>
<p>Start your development server if it’s not already running:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">ng serve</code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="paragraph">
<p>Test it by adding a Bootstrap class (like <code>btn btn-primary</code>) to a button
in <code>app.component.html</code>. If it’s blue, you’re golden.</p>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_4_setting_up_environments"><strong>Step 4: Setting Up Environments</strong></h3>
<div class="paragraph">
<p>Angular provides a built-in way to manage environment-specific
configurations, such as API URLs for development and production. Let’s
configure them.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Run the following command to generate the environment files for
development and production:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">ng generate environments</code></pre>
</div>
</div>
<div class="paragraph">
<p>This will create two files in the <code>src/environments/</code> folder:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>src/
├── environments/
│   ├── environment.development.ts # Development environment
│   └── environment.ts             # Production environment</pre>
</div>
</div>
</li>
<li>
<p>Open both <code>environment.ts</code> and <code>environment.development.ts</code> and add
the <code>apiUrl</code> property. <code>environment.development.ts</code></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">export const environment = {
  production: false,
  apiUrl: "http://localhost:3000", // Replace with your backend's dev URL
};</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>environment.ts</code></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">export const environment = {
  production: true,
  apiUrl: "https://your-production-api.com", // Replace with your backend's prod URL
};</code></pre>
</div>
</div>
</li>
<li>
<p>The <code>environment</code> files are automatically selected based on the build
configuration:</p>
<div class="ulist">
<ul>
<li>
<p><strong>Development</strong>: When running <code>ng serve</code>, Angular replaces
<code>environment.ts</code> with <code>environment.development.ts</code>.</p>
</li>
<li>
<p><strong>Production</strong>: when running <code>ng build --prod</code>, Angular uses
<code>environment.ts</code>.</p>
<div class="paragraph">
<p>You can now use <code>environment.apiUrl</code> in your services to dynamically
switch between development and production APIs.</p>
</div>
</li>
</ul>
</div>
</li>
</ol>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_5_generate_guards_services_and_components"><strong>Step 5: Generate Guards, Services, and Components</strong></h3>
<div class="paragraph">
<p>Let Angular CLI do the heavy lifting for you. Run the following commands
to generate the necessary files:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">ng generate service services/auth
ng generate guard auth/auth
ng generate component pages/login
ng generate component pages/register
ng generate component pages/welcome</code></pre>
</div>
</div>
<div class="paragraph">
<p>What These Commands Do:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Auth Service</strong>: Handles API calls for login, registration, and token
management.</p>
</li>
<li>
<p><strong>Auth Guard</strong>: Protects routes by checking if the user is
authenticated.</p>
</li>
<li>
<p><strong>Login Component</strong>: Provides a form for users to log in.</p>
</li>
<li>
<p><strong>Register Component</strong>: Provides a form for users to register.</p>
</li>
<li>
<p><strong>Welcome Component</strong>: Displays a personalized welcome message for
logged-in users.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>This sets up your folders and boilerplate files, keeping things
organized and modular.</p>
</div>
<div class="sect3">
<h4 id="_project_structure_overview">Project Structure Overview</h4>
<div class="paragraph">
<p>Here’s how your Angular app should look after generating the files:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>src/
├── app/
│   ├── auth/                     # Guards, interceptors, maybe a module
│   │   └── auth.guard.ts
│   ├── pages/                    # Feature components
│   │   ├── login/
│   │   │   ├── login.component.html
│   │   │   ├── login.component.scss
│   │   │   └── login.component.ts
│   │   ├── register/
│   │   │   ├── register.component.html
│   │   │   ├── register.component.scss
│   │   │   └── register.component.ts
│   │   └── welcome/
│   │       ├── welcome.component.html
│   │       ├── welcome.component.scss
│   │       └── welcome.component.ts
│   ├── services/                 # API communication
│   │   └── auth.service.ts
│   ├── shared/                   # Models, utilities, etc. (optional)
│   ├── app.component.html
│   ├── app.component.scss
│   ├── app.component.ts
│   ├── app.config.ts
│   └── app.routes.ts
├── environments/
│   ├── environment.development.ts # Development environment
│   └── environment.ts             # Production environment
├── index.html
├── main.ts
└── style.scss</pre>
</div>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_step_6_the_auth_service_your_api_bridge"><strong>Step 6: The Auth Service – Your API Bridge</strong></h3>
<div class="paragraph">
<p>The <code>AuthService</code> is the backbone of your authentication flow. It
communicates with your backend’s <code>/auth/login</code> and <code>/auth/register</code>
endpoints, manages the JWT in localStorage, and provides utility methods
for token handling.</p>
</div>
<div class="paragraph">
<p>Here’s the complete implementation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/services/auth.service.ts
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { catchError, Observable, tap, throwError } from "rxjs";
import { environment } from "../../environments/environment";

@Injectable({
  providedIn: "root",
})
export class AuthService {
  constructor(private http: HttpClient) {}

  /**
   * Logs in the user by sending their credentials to the backend.
   * Stores the access token in localStorage upon success.
   * @param data - The user's email and password.
   * @returns An observable containing the access token.
   */
  login(data: {
    email: string;
    password: string;
  }): Observable&lt;{ access_token: string }&gt; {
    return this.http
      .post&lt;{ access_token: string }&gt;(`${environment.apiUrl}/auth/login`, data)
      .pipe(
        tap((res) =&gt; localStorage.setItem("access_token", res.access_token)),
        catchError((error) =&gt; {
          const errorMessage =
            error.status === 401
              ? "Invalid email or password. Please try again."
              : "An unexpected error occurred. Please try again later.";
          return throwError(() =&gt; new Error(errorMessage));
        })
      );
  }

  /**
   * Registers a new user by sending their details to the backend.
   * @param data - The user's name, email, password, and role.
   * @returns An observable for the registration process.
   */
  register(data: {
    email: string;
    password: string;
    name: string;
    role: string;
  }): Observable&lt;any&gt; {
    return this.http.post(`${environment.apiUrl}/auth/register`, data).pipe(
      catchError((error) =&gt; {
        const errorMessage =
          error.status === 400
            ? "Registration failed. Please check your input."
            : "An unexpected error occurred. Please try again later.";
        return throwError(() =&gt; new Error(errorMessage));
      })
    );
  }

  /**
   * Logs out the user by removing the access token from localStorage.
   */
  logout(): void {
    localStorage.removeItem("access_token");
  }

  /**
   * Retrieves the stored access token from localStorage.
   * @returns The access token or null if not found.
   */
  getToken(): string | null {
    return localStorage.getItem("access_token");
  }

  /**
   * Checks if the user is authenticated by verifying the presence of a token.
   * @returns A boolean indicating whether the user is authenticated.
   */
  isAuthenticated(): boolean {
    const token = this.getToken();
    return !!token;
  }
}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_7_protecting_routes_with_a_guard"><strong>Step 7: Protecting Routes with a Guard</strong></h3>
<div class="paragraph">
<p>Angular’s <code>CanActivate</code> guard is like a backend middleware for your
routes. Here’s how we check for a valid JWT:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/auth/auth.guard.ts
import { Injectable } from "@angular/core";
import { CanActivate, Router } from "@angular/router";
import { AuthService } from "../services/auth.service";
import { jwtDecode } from "jwt-decode";

@Injectable({ providedIn: "root" })
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(): boolean {
    const token = this.authService.getToken();
    if (!token) {
      this.redirectToLogin();
      return false;
    }

    if (this.isTokenExpired(token)) {
      this.authService.logout();
      this.redirectToLogin();
      return false;
    }

    return true;
  }

  /**
   * Checks if the token is expired.
   * @param token - The JWT token to validate.
   * @returns A boolean indicating whether the token is expired.
   */
  private isTokenExpired(token: string): boolean {
    try {
      const decoded: any = jwtDecode(token);
      return Date.now() &gt; decoded.exp * 1000;
    } catch {
      return true; // Treat invalid tokens as expired
    }
  }

  /**
   * Redirects the user to the login page.
   */
  private redirectToLogin(): void {
    this.router.navigate(["/login"]);
  }
}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_8_login_register_components"><strong>Step 8: Login &amp; Register Components</strong></h3>
<div class="paragraph">
<p>The <code>LoginComponent</code> and <code>RegisterComponent</code> are the core components for
user authentication in the application. Both components use Angular’s
reactive forms to manage user input and validations. They interact with
the <code>AuthService</code> to send requests to the backend for login and
registration functionality. Upon successful operations, they navigate
the user to the appropriate page (<code>/welcome</code> for login and <code>/login</code> for
registration).</p>
</div>
<div class="paragraph">
<p>Key Features</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Reactive Forms</strong>: Both components use Angular’s reactive forms to
handle user input and validations.</p>
</li>
<li>
<p><strong>Validation Rules</strong>: Fields like <code>email</code>, <code>password</code>, and <code>name</code> (for
registration) have validation rules to ensure proper input.</p>
</li>
<li>
<p><strong>Error Handling</strong>: User-friendly error messages are displayed when
login or registration fails.</p>
</li>
<li>
<p><strong>Loading State</strong>: Prevents duplicate submissions by disabling the
submit button while the request is in progress.</p>
</li>
<li>
<p><strong>Navigation</strong>: Redirects users to the appropriate page upon successful
login or registration.</p>
</li>
</ul>
</div>
<hr>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Login Component</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/pages/login/login.component.ts
import { Component } from "@angular/core";
import { Router } from "@angular/router";
import {
  FormBuilder,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from "@angular/forms";
import { AuthService } from "../../services/auth.service";
import { CommonModule } from "@angular/common";

@Component({
  selector: "app-login",
  templateUrl: "./login.component.html",
  styleUrls: ["./login.component.scss"],
  imports: [ReactiveFormsModule, CommonModule],
})
export class LoginComponent {
  form: FormGroup;
  isLoading = false;
  errorMessage: string | null = null;

  constructor(
    private fb: FormBuilder,
    private auth: AuthService,
    private router: Router
  ) {
    this.form = this.fb.group({
      email: ["", [Validators.required, Validators.email]],
      password: ["", [Validators.required, Validators.minLength(6)]],
    });
  }

  onSubmit() {
    if (this.form.invalid) return;

    this.isLoading = true;
    this.errorMessage = null;

    this.auth.login(this.form.value).subscribe({
      next: () =&gt; {
        this.isLoading = false;
        this.router.navigate(["/welcome"]);
      },
      error: (err) =&gt; {
        this.isLoading = false;
        this.errorMessage =
          err.error?.message || "Login failed. Please try again.";
      },
    });
  }
}</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Login HTML</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;!-- src/app/pages/login/login.component.html --&gt;
&lt;form
  [formGroup]="form"
  (ngSubmit)="onSubmit()"
  class="mt-4 p-4 border rounded shadow-sm bg-white"
  style="max-width: 400px; margin: auto"
&gt;
  &lt;h2 class="text-center mb-4"&gt;Login&lt;/h2&gt;

  &lt;div class="mb-3"&gt;
    &lt;input
      formControlName="email"
      type="email"
      class="form-control"
      placeholder="Email"
      [class.is-invalid]="
        form.get('email')?.invalid &amp;&amp; form.get('email')?.touched
      "
      aria-label="Email"
    /&gt;
    &lt;div
      *ngIf="form.get('email')?.invalid &amp;&amp; form.get('email')?.touched"
      class="invalid-feedback"
    &gt;
      Please enter a valid email.
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="mb-3"&gt;
    &lt;input
      formControlName="password"
      type="password"
      class="form-control"
      placeholder="Password"
      [class.is-invalid]="
        form.get('password')?.invalid &amp;&amp; form.get('password')?.touched
      "
      aria-label="Password"
    /&gt;
    &lt;div
      *ngIf="form.get('password')?.invalid &amp;&amp; form.get('password')?.touched"
      class="invalid-feedback"
    &gt;
      Password must be at least 6 characters long.
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div *ngIf="errorMessage" class="alert alert-danger"&gt;
    {{ errorMessage }}
  &lt;/div&gt;

  &lt;button type="submit" class="btn btn-primary w-100" [disabled]="isLoading"&gt;
    &lt;span
      *ngIf="isLoading"
      class="spinner-border spinner-border-sm me-2"
    &gt;&lt;/span&gt;
    Login
  &lt;/button&gt;
&lt;/form&gt;</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Register Component</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/pages/register/register.component.ts
import { Component } from "@angular/core";
import { Router } from "@angular/router";
import {
  FormBuilder,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from "@angular/forms";
import { AuthService } from "../../services/auth.service";
import { CommonModule } from "@angular/common";

@Component({
  selector: "app-register",
  templateUrl: "./register.component.html",
  styleUrls: ["./register.component.scss"],
  imports: [ReactiveFormsModule, CommonModule],
})
export class RegisterComponent {
  form: FormGroup;
  isLoading = false;
  errorMessage: string | null = null;

  constructor(
    private fb: FormBuilder,
    private auth: AuthService,
    private router: Router
  ) {
    this.form = this.fb.group({
      name: ["", [Validators.required]],
      email: ["", [Validators.required, Validators.email]],
      password: ["", [Validators.required, Validators.minLength(6)]],
      role: ["user", [Validators.required]],
    });
  }

  onSubmit() {
    if (this.form.invalid) return;

    this.isLoading = true;
    this.errorMessage = null;

    this.auth.register(this.form.value).subscribe({
      next: () =&gt; {
        this.isLoading = false;
        this.router.navigate(["/login"]);
      },
      error: (err) =&gt; {
        this.isLoading = false;
        this.errorMessage =
          err.error?.message || "Registration failed. Please try again.";
      },
    });
  }
}</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Register HTML</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;form
  [formGroup]="form"
  (ngSubmit)="onSubmit()"
  class="mt-4 p-4 border rounded shadow-sm bg-white"
  style="max-width: 400px; margin: auto"
&gt;
  &lt;h2 class="text-center mb-4"&gt;Register&lt;/h2&gt;

  &lt;div class="mb-3"&gt;
    &lt;input
      formControlName="name"
      type="text"
      class="form-control"
      placeholder="Name"
      [class.is-invalid]="
         form.get('name')?.invalid &amp;&amp; form.get('name')?.touched
       "
      aria-label="Name"
    /&gt;
    &lt;div
      *ngIf="form.get('name')?.invalid &amp;&amp; form.get('name')?.touched"
      class="invalid-feedback"
    &gt;
      Name is required.
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="mb-3"&gt;
    &lt;input
      formControlName="email"
      type="email"
      class="form-control"
      placeholder="Email"
      [class.is-invalid]="
         form.get('email')?.invalid &amp;&amp; form.get('email')?.touched
       "
      aria-label="Email"
    /&gt;
    &lt;div
      *ngIf="form.get('email')?.invalid &amp;&amp; form.get('email')?.touched"
      class="invalid-feedback"
    &gt;
      Please enter a valid email.
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="mb-3"&gt;
    &lt;input
      formControlName="password"
      type="password"
      class="form-control"
      placeholder="Password"
      [class.is-invalid]="
         form.get('password')?.invalid &amp;&amp; form.get('password')?.touched
       "
      aria-label="Password"
    /&gt;
    &lt;div
      *ngIf="form.get('password')?.invalid &amp;&amp; form.get('password')?.touched"
      class="invalid-feedback"
    &gt;
      Password must be at least 6 characters long.
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;div *ngIf="errorMessage" class="alert alert-danger"&gt;
    {{ errorMessage }}
  &lt;/div&gt;

  &lt;button type="submit" class="btn btn-success w-100" [disabled]="isLoading"&gt;
    &lt;span
      *ngIf="isLoading"
      class="spinner-border spinner-border-sm me-2"
    &gt;&lt;/span&gt;
    Register
  &lt;/button&gt;
&lt;/form&gt;</code></pre>
</div>
</div>
</li>
</ol>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_9_welcome_page_static_greeting_and_logout"><strong>Step 9: Welcome Page – Static Greeting and Logout</strong></h3>
<div class="paragraph">
<p>The <code>WelcomeComponent</code> provides a user-friendly page that welcomes the
user after a successful login. It integrates with the existing
AuthService to manage logout functionality but does not attempt to
decode or extract any user-specific data from the access token.</p>
</div>
<div class="paragraph">
<p>Key Features</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Static Greeting</strong>: Display a generic welcome message for all users.</p>
</li>
<li>
<p><strong>Logout Functionality</strong>: Allow users to log out and clear their
session.</p>
</li>
</ul>
</div>
<hr>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Welcome Component</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/pages/welcome/welcome.component.ts
import { Component } from "@angular/core";
import { AuthService } from "../../services/auth.service";
import { Router } from "@angular/router";

@Component({
  selector: "app-welcome",
  templateUrl: "./welcome.component.html",
  styleUrls: ["./welcome.component.scss"],
})
export class WelcomeComponent {
  constructor(private authService: AuthService, private router: Router) {}

  logout(): void {
    this.authService.logout();
    this.router.navigate(["/login"]);
  }
}</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Welcome HTML</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-html" data-lang="html">&lt;!-- src/app/pages/welcome/welcome.component.html --&gt;
&lt;div class="welcome-container text-center mt-5"&gt;
  &lt;h1 class="display-4"&gt;Welcome!&lt;/h1&gt;
  &lt;p class="lead"&gt;We're glad to have you here.&lt;/p&gt;
  &lt;button class="btn btn-primary mt-3" (click)="logout()"&gt;Logout&lt;/button&gt;
&lt;/div&gt;</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Welcome Component SCSS</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scss" data-lang="scss">/* /src/app/pages/welcome/welcome.component.scss */
.welcome-container {
  max-width: 600px;
  margin: auto;
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

h1 {
  color: #343a40;
}

p {
  color: #6c757d;
}</code></pre>
</div>
</div>
</li>
</ol>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_10_routing_lock_down_protected_pages"><strong>Step 10: Routing: Lock Down Protected Pages</strong></h3>
<div class="paragraph">
<p>Alright, now that we’ve got our login, registration, and welcome pages
ready, it’s time to lock things down. We don’t want just anyone
accessing the protected parts of our app, right? That’s where Angular’s
routing and guards come into play. Let’s set up our routes and ensure
only authenticated users can access the welcome page.</p>
</div>
<div class="sect3">
<h4 id="_setting_up_routes">Setting Up Routes</h4>
<div class="paragraph">
<p>In Angular, routes define how users navigate through your app. Here’s
how we’ll structure our routes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>/login</code>: For users to log in.</p>
</li>
<li>
<p><code>/register</code>: For new users to sign up.</p>
</li>
<li>
<p><code>/welcome</code>: A protected page that greets logged-in users.</p>
</li>
<li>
<p><code>/</code>: Redirects to <code>/welcome</code> by default.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Here’s the code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/app/app.routes.ts
import { Routes } from "@angular/router";
import { LoginComponent } from "./pages/login/login.component";
import { RegisterComponent } from "./pages/register/register.component";
import { WelcomeComponent } from "./pages/welcome/welcome.component";
import { AuthGuard } from "./auth/auth.guard";

export const routes: Routes = [
  { path: "", redirectTo: "welcome", pathMatch: "full" },
  { path: "login", component: LoginComponent },
  { path: "register", component: RegisterComponent },
  { path: "welcome", component: WelcomeComponent, canActivate: [AuthGuard] },
];</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is a simple and clean way to define your app’s navigation. Notice
how we’ve added <code>canActivate: [AuthGuard]</code> to the <code>/welcome</code> route?
That’s the magic that protects it.</p>
</div>
</div>
<div class="sect3">
<h4 id="_protecting_routes_with_a_guard">Protecting Routes with a Guard</h4>
<div class="paragraph">
<p>The <code>AuthGuard</code> is like a bouncer for your routes. It checks if the user
is authenticated before letting them in. If they’re not, it redirects
them to the login page.</p>
</div>
</div>
<div class="sect3">
<h4 id="_wiring_it_all_together">Wiring It All Together</h4>
<div class="paragraph">
<p>Now that we’ve defined our routes and guard, let’s hook everything up in
<code>main.ts</code>. Angular v19 makes this super simple with the <code>provideRouter</code>
function:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">// src/main.ts
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";
import { provideRouter } from "@angular/router";
import { routes } from "./app/app.routes";
import { provideHttpClient } from "@angular/common/http";

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes), // Provide the routes
    provideHttpClient(), // Provide the HTTP client
  ],
}).catch((err) =&gt; console.error(err));</code></pre>
</div>
</div>
<div class="paragraph">
<p>No need for a separate <code>AppRoutingModule</code>. Just provide the routes
directly in <code>main.ts</code>, and you’re good to go.</p>
</div>
</div>
<div class="sect3">
<h4 id="_testing_it_out">Testing It Out</h4>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Try Accessing <code>/welcome</code> Without Logging In</strong>:</p>
<div class="ulist">
<ul>
<li>
<p>You should be redirected to <code>/login</code>.</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>Log In and Access <code>/welcome</code></strong>:</p>
<div class="ulist">
<ul>
<li>
<p>After logging in, navigate to <code>/welcome</code>. You should see the
personalized greeting.</p>
</li>
</ul>
</div>
</li>
<li>
<p><strong>Log Out and Try Again</strong>:</p>
<div class="ulist">
<ul>
<li>
<p>After logging out, try accessing <code>/welcome</code> again. You should be
redirected to <code>/login</code>.</p>
</li>
</ul>
</div>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="_why_this_matters">Why This Matters</h4>
<div class="paragraph">
<p>For backend developers, this should feel familiar. Think of the
<code>AuthGuard</code> as middleware for your routes. It ensures that only
authenticated users can access certain parts of your app, just like how
you’d protect API endpoints on the server side.</p>
</div>
<div class="paragraph">
<p>By combining Angular’s routing with guards, you’ve got a solid
foundation for building secure, user-friendly apps. And the best part?
It’s modular and easy to extend. Want to add role-based access? Just
tweak the guard. Need to protect more routes? Add <code>canActivate</code> to them.</p>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_whats_next"><strong>What’s Next?</strong></h3>
<div class="paragraph">
<p>You’ve got a working Angular app wired to your backend, protected with
route guards and powered by JWT auth. Next up, we’ll level things up
with some Angular 19 enhancements and best practices.</p>
</div>
<div class="paragraph">
<p>👉 <strong>Part 4: Angular 19 Deep Dive</strong></p>
</div>
<div class="paragraph">
<p>We’ll cover:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>🧠 <strong>Signals vs Observables</strong> — When to use which and why</p>
</li>
<li>
<p>🔁 <code>@if</code>, <code>@for</code>, and <code>defer</code> blocks — Smarter templates with better
control</p>
</li>
<li>
<p>⚡ <strong>Change detection and performance tuning</strong></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This part’s optional, but worth it if you want your Angular app to be
leaner, faster, and future-ready.</p>
</div>
<div class="paragraph">
<p>For now, pat yourself on the back—you’ve just implemented a secure,
modern routing system in Angular. 🚀</p>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>AI plugins for code development</title>
		<link>https://blog.lunatech.com//posts/2025-05-02-ai-plugins-for-code-development</link>
		
		<dc:creator><![CDATA[Rajendra Maniyal]]></dc:creator>
        <pubDate>2025-05-02T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[AI]]></category>
                }
             {
            <category><![CDATA[IntelliJ AI Plugins]]></category>
                }
             {
            <category><![CDATA[Local LLMs]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-05-02-ai-plugins-for-code-development</guid>

					<description>
                        <![CDATA[ Recently, I experimented with integrating AI into my IntelliJ IDEA setup for JVM development, and I wanted to share the steps I followed. It turned out to be really helpful, so maybe this guide can assist someone else in getting started too!]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Recently, I experimented with integrating AI into my IntelliJ IDEA setup for JVM development, and I wanted to share the steps I followed. It turned out to be really helpful, so maybe this guide can assist someone else in getting started too!</p>
</div>
<div class="paragraph">
<p>IntelliJ is one of the preferred IDE for Java, Scala and Kotlin development. I have been using the IntelliJ IDEA with plugins for AI, which allows me to use Local LLMs to generate code suggestions, refactor my code and even write tests for me.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_i_did">What I did</h2>
<div class="sectionbody">
<div class="paragraph">
<p><strong>Step 1: Install Ollama</strong></p>
</div>
<div class="paragraph">
<p>First, visit <a href="https://ollama.com/">Ollama</a> and download the version for your operating system. Follow the simple installation steps.</p>
</div>
<div class="paragraph">
<p>Open your terminal and run <code>ollama pull llama3</code> to download the model. Start the model by running <code>ollama serve llama3</code>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
Choosing the right model is very important .
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><strong>Step 2: IntelliJ Plugins</strong></p>
</div>
<div class="paragraph">
<p>I tested a few plugins and found Continue.dev really useful:</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
A list of plugins at the bottom of this article with links
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Continue.dev
Helps with code completion, converting comments into code, and debugging tips.
Works locally (privacy-friendly), quick.
Needs decent hardware resources.</p>
</div>
<div class="paragraph">
<p><strong>Step 3: Setting Up Continue.dev with IntelliJ</strong></p>
</div>
<div class="paragraph">
<p>Install the Plugin:
Open IntelliJ IDEA, navigate to Settings &#8594; Plugins, search for "Continue.dev", and install it.</p>
</div>
<div class="paragraph">
<p>Connect to Ollama:
Open the Continue.dev settings and add the local Ollama server URL (<code><a href="http://localhost:11434" class="bare">http://localhost:11434</a></code>).</p>
</div>
<div class="paragraph">
<p><strong>Step 4: Exploring AI Features</strong></p>
</div>
<div class="paragraph">
<p>Code Suggestions:
The plugin provided accurate code completions immediately, significantly speeding up my workflow.</p>
</div>
<div class="paragraph">
<p>Generating Code from Comments:
I tried writing simple English comments, and Continue.dev translated them into functioning code snippets effortlessly.</p>
</div>
<div class="paragraph">
<p>Debugging:
Even when intentionally making small errors, the plugin quickly suggested effective fixes.</p>
</div>
<div class="paragraph">
<p><strong>Step 5: AI-Assisted Refactoring</strong></p>
</div>
<div class="paragraph">
<p>I highlighted some messy code.
Using the AI suggestions via right-click helped clean up and optimize the code efficiently.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_tips_for_best_results">Tips for Best Results:</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Regularly update plugins and AI models for optimal performance.</p>
</div>
<div class="paragraph">
<p>If hardware resources are limited, experiment with smaller models initially.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_intellij_idea_plugins_supporting_local_llm_integration">IntelliJ IDEA Plugins Supporting Local LLM Integration</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 14.2857%;">
<col style="width: 28.5714%;">
<col style="width: 28.5714%;">
<col style="width: 28.5715%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Plugin</th>
<th class="tableblock halign-left valign-top">Features</th>
<th class="tableblock halign-left valign-top">Pros</th>
<th class="tableblock halign-left valign-top">Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong><a href="https://plugins.jetbrains.com/plugin/22707-continue">Continue.dev</a></strong></p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="ulist">
<ul>
<li>
<p>Code completion</p>
</li>
<li>
<p>Natural language to code generation</p>
</li>
<li>
<p>Inline code explanations</p>
</li>
<li>
<p>Supports multiple local LLM providers</p>
</li>
</ul>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- Open-source
- Highly customizable
- Supports various local LLMs like Ollama, LM Studio, GPT4All</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- May require manual configuration for optimal performance</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong><a href="https://plugins.jetbrains.com/plugin/24169-devoxxgenie">DevoxxGenie</a></strong></p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="ulist">
<ul>
<li>
<p>Code review and explanation</p>
</li>
<li>
<p>Unit test generation</p>
</li>
<li>
<p>Retrieval-Augmented Generation (RAG)</p>
</li>
<li>
<p>Integration with various local LLMs</p>
</li>
</ul>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- Fully Java-based
- Rich feature set including RAG and Git Diff viewer
- Supports multiple local LLMs</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- Interface may be overwhelming for beginners</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong><a href="https://plugins.jetbrains.com/plugin/21056-proxy-ai">Proxy AI</a></strong></p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="ulist">
<ul>
<li>
<p>Connects IntelliJ IDEA with locally running LLMs</p>
</li>
<li>
<p>Provides AI assistance features</p>
</li>
</ul>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- Open-source
- Simple setup for local LLM integration</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- Limited feature set compared to other plugins</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong><a href="https://plugins.jetbrains.com/plugin/24372-codegpt-chat&#8212;&#8203;ai-agents">CodeGPT</a></strong></p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="ulist">
<ul>
<li>
<p>AI-powered code suggestions</p>
</li>
<li>
<p>Chat interface within IntelliJ IDEA</p>
</li>
<li>
<p>Supports local LLMs via LM Studio</p>
</li>
</ul>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- User-friendly interface
- Supports multiple programming languages</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- May require additional setup for local LLM integration</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong><a href="https://plugins.jetbrains.com/plugin/22282-jetbrains-ai-assistant">JetBrains AI Assistant</a></strong></p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="ulist">
<ul>
<li>
<p>AI-driven code suggestions</p>
</li>
<li>
<p>Code explanations and documentation generation</p>
</li>
<li>
<p>Integration with local LLMs</p>
</li>
</ul>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- Official JetBrains plugin
- Seamless integration with IntelliJ IDEA</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">- May have limited customization compared to open-source alternatives</p></td>
</tr>
</tbody>
</table>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Part 2: Backend Setup with NestJS</title>
		<link>https://blog.lunatech.com//posts/2025-04-22-part-2%3A-backend-setup-with-nestjs</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-04-22T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[angular]]></category>
                }
             {
            <category><![CDATA[nestjs]]></category>
                }
             {
            <category><![CDATA[postgresql]]></category>
                }
             {
            <category><![CDATA[typeorm]]></category>
                }
             {
            <category><![CDATA[jwt]]></category>
                }
             {
            <category><![CDATA[authentication]]></category>
                }
             {
            <category><![CDATA[frontend]]></category>
                }
             {
            <category><![CDATA[typescript]]></category>
                }
             {
            <category><![CDATA[nodejs]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-04-22-part-2%3A-backend-setup-with-nestjs</guid>

					<description>
                        <![CDATA[ With our project vision and stack laid out in Part 1, it’s time to build the]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>With our project vision and stack laid out in Part 1, it’s time to build the
backend.
In this part, we’ll scaffold a <strong>NestJS</strong> project, connect it to <strong>PostgreSQL</strong>
via <strong>TypeORM</strong>, and implement secure <strong>JWT-based authentication</strong>.</p>
</div>
<div class="paragraph">
<p>By the end of this part, you’ll have:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A working NestJS app connected to PostgreSQL</p>
</li>
<li>
<p>A <code>User</code> entity with hashed passwords</p>
</li>
<li>
<p>Endpoints for registration and login</p>
</li>
<li>
<p>JWT authentication using guards and strategies</p>
</li>
<li>
<p>CORS enabled to allow Angular frontend communication</p>
</li>
</ul>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_project_structure_overview"><strong>Project Structure Overview</strong></h3>
<div class="paragraph">
<p>Once set up, your backend folder will look like this:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>src/
├── app.module.ts
├── main.ts
├── auth/
│   ├── auth.controller.ts
│   ├── auth.module.ts
│   ├── auth.service.ts
│   ├── dto/
│   │   ├── login.dto.ts
│   │   └── register.dto.ts
│   └── jwt/
│       └── jwt.strategy.ts
├── users/
│   ├── user.entity.ts
│   ├── users.controller.ts
│   ├── users.module.ts
│   └── users.service.ts
.env</pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_goals_for_part_2"><strong>Goals for Part 2</strong></h3>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Scaffold a NestJS project with PostgreSQL and TypeORM</p>
</li>
<li>
<p>Create a <code>User</code> entity, DTOs with validation, and an Auth module</p>
</li>
<li>
<p>Implement registration and login with password hashing</p>
</li>
<li>
<p>Add JWT authentication with guards and strategy</p>
</li>
<li>
<p>Enable CORS for frontend connectivity</p>
</li>
</ol>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_1_run_postgresql_and_set_environment_variables"><strong>Step 1: Run PostgreSQL and Set Environment Variables</strong></h3>
<div class="paragraph">
<p>You can use either Docker or Podman.
Run <strong>one</strong> of the following commands in your terminal:</p>
</div>
<div class="paragraph">
<p><strong>Docker:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">docker run --name pg-nest \
  -e POSTGRES_USER=nestuser \
  -e POSTGRES_PASSWORD=nestpass \
  -e POSTGRES_DB=nestdb \
  -p 5432:5432 \
  -d postgres</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Podman:</strong></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">podman run --name pg-nest \
  -e POSTGRES_USER=nestuser \
  -e POSTGRES_PASSWORD=nestpass \
  -e POSTGRES_DB=nestdb \
  -p 5432:5432 \
  -d postgres</code></pre>
</div>
</div>
<div class="paragraph">
<p>Once the project is created in Step 2, add a <code>.env</code> file to your root:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>DB_HOST=localhost DB_PORT=5432 DB_USERNAME=nestuser DB_PASSWORD=nestpass
DB_NAME=nestdb JWT_SECRET=dev_secret BCRYPT_SALT_ROUNDS=10</pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_2_scaffold_the_project_and_install_dependencies"><strong>Step 2: Scaffold the Project and Install Dependencies</strong></h3>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">nest new backend
cd backend</code></pre>
</div>
</div>
<div class="paragraph">
<p>Install project dependencies:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm install @nestjs/typeorm typeorm pg @nestjs/jwt passport-jwt @nestjs/passport bcrypt class-validator class-transformer dotenv</code></pre>
</div>
</div>
<div class="paragraph">
<p>At the top of <code>main.ts</code>, import environment variables:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import "dotenv/config";</code></pre>
</div>
</div>
<div class="paragraph">
<p>Enable CORS:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">app.enableCors({
  origin: "http://localhost:4200",
  credentials: true,
});</code></pre>
</div>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>✅ <strong>Tip</strong>: For production, consider using <code>@nestjs/config</code> for cleaner
environment management.</p>
</div>
</blockquote>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_3_configure_typeorm"><strong>Step 3: Configure TypeORM</strong></h3>
<div class="paragraph">
<p>In <code>app.module.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { UsersModule } from "./users/users.module";
import { AuthModule } from "./auth/auth.module";

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "postgres",
      host: process.env.DB_HOST,
      port: parseInt(process.env.DB_PORT, 10),
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME,
      entities: [__dirname + "/**/*.entity{.ts,.js}"],
      synchronize: true, // ⚠️ Don't use this in production — it'll drop/recreate tables
    }),
    UsersModule,
    AuthModule,
  ],
})
export class AppModule {}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_4_create_the_user_module_and_entity"><strong>Step 4: Create the User Module and Entity</strong></h3>
<div class="paragraph">
<p>Generate boilerplate:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">nest g module users
nest g service users
nest g controller users</code></pre>
</div>
</div>
<div class="paragraph">
<p>In <code>users/user.entity.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Exclude } from "class-transformer";
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  name: string;

  @Column()
  @Exclude()
  password: string;

  @Column()
  role: string;
}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_5_set_up_the_auth_module"><strong>Step 5: Set Up the Auth Module</strong></h3>
<div class="paragraph">
<p>Generate files:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">nest g module auth
nest g service auth
nest g controller auth</code></pre>
</div>
</div>
<div class="sect3">
<h4 id="_step_5a_create_dtos_with_validation">Step 5a: Create DTOs with Validation</h4>
<div class="paragraph">
<p>In <code>auth/dto/register.dto.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { IsEmail, IsNotEmpty, MinLength } from "class-validator";

export class RegisterDto {
  @IsEmail()
  email: string;

  @MinLength(6)
  password: string;

  @IsNotEmpty()
  name: string;

  @IsNotEmpty()
  role: string;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>These are like your request payload models with annotations.
Think <code>@NotEmpty</code>, <code>@Email</code>, etc.
The validation logic is handled globally (we’ll wire that up in <code>main.ts</code>
using <code>ValidationPipe</code>).</p>
</div>
<div class="paragraph">
<p>In <code>auth/dto/login.dto.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { IsEmail, MinLength } from "class-validator";

export class LoginDto {
  @IsEmail()
  email: string;

  @MinLength(6)
  password: string;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Enable validation globally in <code>main.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { ValidationPipe } from "@nestjs/common";

app.useGlobalPipes(new ValidationPipe({ whitelist: true }));</code></pre>
</div>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_step_6_implement_usersservice"><strong>Step 6: Implement UsersService</strong></h3>
<div class="paragraph">
<p>This service handles persistence logic using TypeORM’s repository pattern.
In <code>users.service.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { User } from "./user.entity";

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private repo: Repository&lt;User&gt;
  ) {}

  create(data: Partial&lt;User&gt;) {
    const user = this.repo.create(data);
    return this.repo.save(user);
  }

  findByEmail(email: string) {
    return this.repo.findOne({ where: { email } });
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Again, if you’re used to JPA, this is just standard repository stuff.</p>
</div>
<div class="paragraph">
<p>In <code>users.module.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./user.entity";
import { UsersService } from "./users.service";
import { UsersController } from "./users.controller";

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UsersService],
  controllers: [UsersController],
  exports: [UsersService],
})
export class UsersModule {}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_7_build_authservice"><strong>Step 7: Build AuthService</strong></h3>
<div class="paragraph">
<p>This is where registration and login happens.
We hash passwords with <code>bcrypt</code>, and return a JWT if login succeeds.</p>
</div>
<div class="paragraph">
<p>You’ll notice:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">delete user.password;</code></pre>
</div>
</div>
<div class="paragraph">
<p>It manually removes the password before returning the user — feels a bit
hacky, but we’ve also used <code>@Exclude()</code> in the entity, so this is just being
extra cautious.</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>⚠️ We’re using both <code>@Exclude()</code> (to hide the password when transforming
entities) and <code>delete user.password</code> as a backup.
Depending on how Nest returns the object — directly vs. through a
serialization step — the password field might still leak through without
this extra guard.</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p>In <code>auth.service.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Injectable, UnauthorizedException } from "@nestjs/common";
import * as bcrypt from "bcrypt";
import { JwtService } from "@nestjs/jwt";
import { UsersService } from "../users/users.service";
import { RegisterDto } from "./dto/register.dto";
import { LoginDto } from "./dto/login.dto";

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService
  ) {}

  async register(dto: RegisterDto) {
    const existing = await this.usersService.findByEmail(dto.email);
    if (existing) throw new UnauthorizedException("Email already in use");

    const hashed = await bcrypt.hash(dto.password, 10);
    const user = await this.usersService.create({
      ...dto,
      password: hashed,
    });
    delete user.password;
    return user;
  }

  async login(dto: LoginDto) {
    const user = await this.usersService.findByEmail(dto.email);
    const valid = user &amp;&amp; (await bcrypt.compare(dto.password, user.password));
    if (!valid) throw new UnauthorizedException("Invalid credentials");

    const payload = { sub: user.id, role: user.role };
    return { access_token: this.jwtService.sign(payload) };
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In <code>auth.module.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
import { AuthService } from "./auth.service";
import { AuthController } from "./auth.controller";
import { UsersModule } from "../users/users.module";
import { JwtStrategy } from "./jwt/jwt.strategy";

@Module({
  imports: [
    UsersModule,
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: { expiresIn: "1d" },
    }),
  ],
  providers: [AuthService, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}</code></pre>
</div>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_8_jwt_strategy_and_guards"><strong>Step 8: JWT Strategy and Guards</strong></h3>
<div class="paragraph">
<p>Here we set up Passport’s JWT strategy.
If you’re new to Passport: it’s just NestJS’s way of plugging in different
auth strategies.</p>
</div>
<div class="paragraph">
<p>Create the strategy file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">touch src/auth/jwt/jwt.strategy.ts</code></pre>
</div>
</div>
<div class="paragraph">
<p>In <code>jwt.strategy.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: process.env.JWT_SECRET,
    });
  }

  validate(payload: any) {
    return { id: payload.sub, role: payload.role };
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This function runs once the JWT is verified.
It attaches the returned object to <code>req.user</code>.</p>
</div>
<div class="paragraph">
<p>So if you hit a route with a valid JWT, this is what gets injected.</p>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_9_connect_auth_routes"><strong>Step 9: Connect Auth Routes</strong></h3>
<div class="paragraph">
<p>In <code>auth.controller.ts</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ts" data-lang="ts">import { Controller, Post, Body } from "@nestjs/common";
import { AuthService } from "./auth.service";
import { RegisterDto } from "./dto/register.dto";
import { LoginDto } from "./dto/login.dto";

@Controller("auth")
export class AuthController {
  constructor(private authService: AuthService) {}

  @Post("register")
  register(@Body() dto: RegisterDto) {
    return this.authService.register(dto);
  }

  @Post("login")
  login(@Body() dto: LoginDto) {
    return this.authService.login(dto);
  }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Two routes here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>POST /auth/register</code> → Creates a user</p>
</li>
<li>
<p><code>POST /auth/login</code> → Validates user and returns a token</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Nice and clean.</p>
</div>
<hr>
</div>
<div class="sect2">
<h3 id="_step_10_test_it"><strong>Step 10: Test It</strong></h3>
<div class="paragraph">
<p>Start your server:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm run start:dev</code></pre>
</div>
</div>
<div class="paragraph">
<p>Use Postman or Insomnia:</p>
</div>
<div class="sect3">
<h4 id="_register">Register</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-http" data-lang="http">POST /auth/register
Content-Type: application/json

{
  "email": "test@example.com",
  "password": "123456",
  "name": "Test User",
  "role": "user"
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_login">Login</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-http" data-lang="http">POST /auth/login
Content-Type: application/json

{
  "email": "test@example.com",
  "password": "123456"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Response:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
  "access_token": "&lt;JWT_TOKEN&gt;"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Use this token to access protected routes with:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>Authorization: Bearer &lt;JWT_TOKEN&gt;</pre>
</div>
</div>
<hr>
</div>
</div>
<div class="sect2">
<h3 id="_recap"><strong>Recap</strong></h3>
<div class="paragraph">
<p>You now have:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A functional NestJS backend with PostgreSQL</p>
</li>
<li>
<p>User registration and login with secure hashed passwords</p>
</li>
<li>
<p>JWT-based authentication strategy and guards</p>
</li>
<li>
<p>DTO validation and global pipes</p>
</li>
<li>
<p>Environment config and CORS enabled for the frontend</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>👉 <strong>Next up (Part 3): We’ll switch gears and start building the Angular
frontend — hooking it up to this backend, wiring in JWT auth, and securing
client-side routes.</strong></p>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>GenAI: Optimizing Local Large Language Models Performance</title>
		<link>https://blog.lunatech.com//posts/2025-04-17-genai%3A-optimizing-local-large-language-models-performance</link>
		
		<dc:creator><![CDATA[Radek Kargul]]></dc:creator>
        <pubDate>2025-04-17T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[gen-ai]]></category>
                }
             {
            <category><![CDATA[llm]]></category>
                }
             {
            <category><![CDATA[generative-ai]]></category>
                }
             {
            <category><![CDATA[local-llm]]></category>
                }
             {
            <category><![CDATA[ollama]]></category>
                }
             {
            <category><![CDATA[quantization]]></category>
                }
             {
            <category><![CDATA[model-optimization]]></category>
                }
             {
            <category><![CDATA[neural-networks]]></category>
                }
             {
            <category><![CDATA[model-inference]]></category>
                }
             {
            <category><![CDATA[open-source]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-04-17-genai%3A-optimizing-local-large-language-models-performance</guid>

					<description>
                        <![CDATA[ Local large language models (LLMs) are becoming more capable and accessible than ever — but to truly unlock their power, you need to know how to optimize them.]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Local large language models (LLMs) are becoming more capable and accessible than ever — but to truly unlock their power, you need to know how to optimize them.
Whether you&#8217;re running AI on an M-series MacBook or a 2019 Intel machine, there are tricks to get better speed, quality, and control.</p>
</div>
<div class="paragraph">
<p>In the final session of our GenAI series (after covering Local Dev, RAG, and Agents), we explored the real-world performance tuning of local LLMs.
Here&#8217;s what we covered 👇</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_1_running_llms_on_your_laptop">1. Running LLMs on Your Laptop</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_apple_silicon_vs_intel_macs">Apple Silicon vs Intel Macs</h3>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 42.8571%;">
<col style="width: 28.5714%;">
<col style="width: 28.5715%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Feature</th>
<th class="tableblock halign-left valign-top">Apple Silicon (M1/M2/M3/M4)</th>
<th class="tableblock halign-left valign-top">Intel Mac (e.g. 2019 MBP)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">CPU &amp; GPU</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Unified on one chip (SoC)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Separate chips for CPU and GPU</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Memory</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Shared Unified Memory Architecture</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">RAM for CPU, VRAM for GPU</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Model performance</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Fast, efficient, great for LLMs</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Slower, GPU mostly unused</p></td>
</tr>
</tbody>
</table>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>M-series chips shine for local AI workloads thanks to unified memory.</p>
</div>
<div class="paragraph">
<p>Intel Macs can still work well but rely entirely on CPUs and may struggle with larger models.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_what_can_you_run">What Can You Run?</h3>
<div class="paragraph">
<p>Models are measured by <strong>parameters</strong>, typically in billions (e.g., 3B, 7B, 13B).
More parameters = more "intelligence" — but also more memory use.</p>
</div>
<div class="paragraph">
<p>Use quantization (more below!) to fit larger models, even on machines with 8–16 GB RAM.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_2_quantization_making_llms_lighter">2. Quantization: Making LLMs Lighter</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_what_is_quantization">What is Quantization?</h3>
<div class="paragraph">
<p>Quantization reduces the <strong>precision of the numbers</strong> in a model — trading a little accuracy for huge gains in size and speed.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 40%;">
<col style="width: 40%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Format</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Typical Use</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">FP32</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Full precision</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Training</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">FP16</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Half precision</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Deployment</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">INT8</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Quantized</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Light inference (some loss)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">INT4</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Heavily quantized</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Fast local inference</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">INT2–3</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Experimental</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Ultra-lightweight, niche</p></td>
</tr>
</tbody>
</table>
<div class="exampleblock">
<div class="content">
<div class="paragraph">
<p>LLaMA2-70B goes from <strong>138GB (FP16)</strong> to <strong>42GB (INT4)</strong> — a huge saving!</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_is_gguf">What is GGUF?</h3>
<div class="paragraph">
<p><code>GGUF</code> stands for <strong>GPT-Generated Unified Format</strong>.
It’s a modern, standardized file format designed for running <strong>quantized large language models (LLMs) locally</strong>.</p>
</div>
<div class="sect3">
<h4 id="_why_gguf">Why GGUF?</h4>
<div class="paragraph">
<p>GGUF makes loading and using models in tools like <code>llama.cpp</code>, <code>Ollama</code>, or <code>LM Studio</code>.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Feature</th>
<th class="tableblock halign-left valign-top">Benefit</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">🧳 Compact</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Stores quantized models in a smaller, efficient format</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">🧠 Self-contained</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Includes weights, tokenizer, metadata, and vocab in one file</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">⚡ Fast</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optimized for quick loading and inference</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">🔧 Flexible</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supports various quantization formats like <code>Q4_K_M</code>, <code>Q5_K_S</code>, etc.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="_tools_that_support_gguf">Tools that Support GGUF</h4>
<div class="ulist">
<ul>
<li>
<p><code>llama.cpp</code> – Core backend for CPU/GPU inference</p>
</li>
<li>
<p><code>Ollama</code> – CLI + API for local models</p>
</li>
<li>
<p><code>LM Studio</code> – Desktop GUI for Mac/Windows/Linux</p>
</li>
<li>
<p><code>text-generation-webui</code> – Powerful browser-based frontend</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_example_gguf_model_filename">Example GGUF Model Filename</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">mistral-7b-instruct-v0.1.Q4_K_M.gguf</code></pre>
</div>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Part</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>mistral-7b-instruct</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Model type and size</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>v0.1</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Model version</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Q4_K_M</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Quantization type (4-bit, medium group)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>.gguf</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">File format extension</p></td>
</tr>
</tbody>
</table>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>Think of a <code>.gguf</code> file as an <strong>AI-in-a-box</strong> — it includes everything the model needs to run locally, compressed and ready to go.</p>
</div>
</blockquote>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_k_quant_types_for_gguf_models">K-Quant Types (for GGUF Models)</h3>
<div class="paragraph">
<p>When downloading quantized models (especially in GGUF format), you&#8217;ll often see suffixes like <code>Q4_K_S</code>, <code>Q5_K_M</code>, or <code>Q6_K_L</code>.
These aren&#8217;t just random labels — they define <strong>how the quantization is applied</strong>, and they directly affect <strong>model quality vs. performance</strong>.</p>
</div>
<div class="paragraph">
<p>The <code>K</code> in these names refers to the <strong>quantization group size and method</strong>, which influences:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>how much precision is preserved;</p>
</li>
<li>
<p>how fast the model can run;</p>
</li>
<li>
<p>how much RAM is required.</p>
</li>
</ul>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Suffix</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>K_S</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Small group quantization</strong>
Fastest and most memory-efficient. It compresses more aggressively, which means it&#8217;s ideal when you&#8217;re on a tight memory budget or running on weaker hardware — but output quality might noticeably degrade on complex tasks.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>K_M</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Medium group quantization</strong>
A great balance of speed, memory use, and output quality. It&#8217;s the "safe middle ground" for most users running 4–7B models locally. If you&#8217;re unsure where to start, this is a solid default.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>K_L</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Large group quantization</strong>
More conservative compression — keeps more precision, giving higher-quality outputs. Slower and uses more RAM, but closer to non-quantized behavior. Ideal for tasks requiring accurate and nuanced responses.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The difference isn&#8217;t <strong>just</strong> in speed — it&#8217;s also in how much subtle detail the model retains in its responses.</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>“Think of <code>K_S</code>, <code>K_M</code>, and <code>K_L</code> as image compression presets:
<strong>Small</strong> is low-res JPEG, <strong>Medium</strong> is standard HD, <strong>Large</strong> is almost RAW quality.”</p>
</div>
</blockquote>
</div>
</div>
<div class="sect2">
<h3 id="_what_is_quantization_used_for">What is Quantization used for?</h3>
<div class="paragraph">
<p>Quantization is a trade-off between size, speed, and accuracy.
For some perspective, here’s a rough guide on how quantization is used in the LLM world:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Task</th>
<th class="tableblock halign-left valign-top">Quantization</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Model training</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">FP32 (that&#8217;s why it is so expensive to train models, to get that knowledge accurate)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">For deployment</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Usually FP16 (for speed)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Local models</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Unused INT4 (for speed and accuracy)</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="_why_not_just_use_a_smaller_model">Why Not Just Use a Smaller Model?</h3>
<div class="ulist">
<ul>
<li>
<p>Models under 3B can run easily — but often lack reasoning or language nuance.</p>
</li>
<li>
<p>Quantization gives you <strong>the best of both worlds</strong>: keep a 7B+ model’s brain but shrink the size.</p>
</li>
</ul>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>“It’s like watching a 4K movie compressed to 1080p — smaller, still looks good.”</p>
</div>
</blockquote>
</div>
</div>
<div class="sect2">
<h3 id="_quantized_models_in_action_example">Quantized Models In Action (Example)</h3>
<div class="paragraph">
<p>In this example, we consider <a href="https://ollama.com/library/qwen2.5/tags">qwen2.5</a>, a 14B model with quantized versions available in <code>Ollama</code>.
We will focus on different quantization levels of the 14B model.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s have a look at how different models deal with the following prompt:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-text" data-lang="text">Explain recursion to a 10-year-old in one paragraph.</code></pre>
</div>
</div>
<div class="paragraph">
<p>To run the models, execute one of the following prompts, starting with Q4_0:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell" data-lang="shell">ollama run qwen2.5:14b-instruct-q4_0
ollama run qwen2.5:14b-instruct-q8_0
ollama run qwen2.5:14b-instruct-q2_K
ollama run qwen2.5:14b-instruct-fp16</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example, let&#8217;s start with Q4_0:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell" data-lang="shell">ollama run qwen2.5:14b-instruct-q4_0</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now that the model is loaded, we can run the prompt:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell" data-lang="shell">"Explain recursion to a 10-year-old in one paragraph."</code></pre>
</div>
</div>
<div class="paragraph">
<p>Pay attention to the response time and the memory usage.
Compare it with the other models.</p>
</div>
<div class="paragraph">
<p>You may have noticed there is not much difference in quality between the Q4_0 and Q8_0 models, but the Q2_K model is much faster and smaller.
Perfect for showing the quality/speed trade-off in action, and how to adjust for your needs.
This does not necessarily mean that the behavior is the same for other prompts or tasks.
You have to try this for yourself and see what works best for you on your machine.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_3_tuning_parameters_in_ollama">3. Tuning Parameters in Ollama</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Using <strong>Ollama</strong>?
You can change some parameter settings of the local models based on your preference, for example, a more deterministic response, or a more creative one.</p>
</div>
<div class="paragraph">
<p>Let us consider the <code>llama3</code> model, we can run it with the following command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-shell" data-lang="shell">ollama run llama3</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can set these parameters after the model is loaded:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>/set parameter &lt;parameter&gt; &lt;value&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>So, for example, to set <code>temperature</code> to 1.0:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>/set parameter temperature 1.0</pre>
</div>
</div>
<div class="paragraph">
<p>And then we set <code>top_p</code> to 0.9:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>/set parameter top_p 0.9</pre>
</div>
</div>
<div class="paragraph">
<p>In the example above, we set the <code>temperature</code> to 1.0, a more creative response, and <code>top_p</code> to 0.9, a more deterministic response.
Parameter <code>temperature</code> adds randomness.
The lower the value, the more focused and deterministic the model response.
The higher the value, the more creative and varied the response.
Parameter <code>top_p</code> picks from the smallest possible set of words whose cumulative probability adds up to <code>p</code>.
It controls diversity — higher values mean more diverse and creative responses, and lower values make responses more focused.</p>
</div>
<div class="paragraph">
<p>Here are some more common parameters you can tune:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Param</th>
<th class="tableblock halign-left valign-top">What it Does</th>
<th class="tableblock halign-left valign-top">Typical Values</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">num_ctx</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Context size (how much it remembers)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">2048–4096</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">top_k</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Limits top options for output</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">40–100</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">top_p</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Controls diversity</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0.8–0.95</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">temperature</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Controls creativity</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0.6–0.8 (chat), 0.3–0.6 (code)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">repeat_penalty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Avoids repeating phrases</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1.1–1.3</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">threads</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Number of CPU threads (config only)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Match to physical cores</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>If you want to learn more about the parameters, you can find some extra information <a href="https://learnprompting.org/blog/llm-parameters?srsltid=AfmBOoorA2XSH8rxtzvLZcSstK1mp8Hzrj-o5uJRIXKOHVUhAmvcsW5u">here</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_resources">Resources</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://www.tensorops.ai/post/what-are-quantized-llms">What Are Quantized LLMs – TensorOps</a></p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=K75j8MkwgJ0">Quantization Explained – YouTube</a></p>
</li>
<li>
<p><a href="https://pieces.app/blog/llm-parameters">LLM Parameters – Pieces Blog</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_final_thoughts">Final Thoughts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Running LLMs locally is no longer science fiction — it&#8217;s practical, efficient, and private.
With just a bit of tuning and the right model format, your laptop becomes an AI powerhouse.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Part 1: Introduction and Stack Breakdown for the Angular + NestJS Auth Boilerplate</title>
		<link>https://blog.lunatech.com//posts/2025-04-04-part-1-introduction-&amp;-stack-breakdown-for-the-angular-+-nestjs-auth-boilerplate</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-04-04T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[angular]]></category>
                }
             {
            <category><![CDATA[nestjs]]></category>
                }
             {
            <category><![CDATA[postgresql]]></category>
                }
             {
            <category><![CDATA[typeorm]]></category>
                }
             {
            <category><![CDATA[jwt]]></category>
                }
             {
            <category><![CDATA[authentication]]></category>
                }
             {
            <category><![CDATA[frontend]]></category>
                }
             {
            <category><![CDATA[typescript]]></category>
                }
             {
            <category><![CDATA[nodejs]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-04-04-part-1-introduction-&amp;-stack-breakdown-for-the-angular-+-nestjs-auth-boilerplate</guid>

					<description>
                        <![CDATA[ Welcome to the first part in this series on building a full-stack]]></description>
                    <content:encoded><![CDATA[
                    <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the first part in this series on building a full-stack
authentication boilerplate with <strong>Angular</strong>, <strong>NestJS</strong>, and <strong>PostgreSQL</strong>.</p>
</div>
<div class="paragraph">
<p>If you’re a backend developer comfortable with APIs, databases, and business
logic—but frontend frameworks feel like foreign territory—this series is for
you.
We’ll walk through the full stack, showing you how to build real
authentication flows while picking up modern Angular features along the way.</p>
</div>
<div class="paragraph">
<p>By the end, you’ll have a production-ready authentication boilerplate you
can reuse in your own projects—or hand off confidently to frontend
collaborators.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_why_angular_nestjs">Why Angular + NestJS?</h3>
<div class="paragraph">
<p>We’re using <strong>Angular</strong> on the frontend and <strong>NestJS</strong> on the backend.
Both are built in <strong>TypeScript</strong>, so you get a unified development experience
without switching mental models.</p>
</div>
<div class="paragraph">
<p>Here’s why this stack works well together:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Angular</strong> is opinionated, scalable, and modular—perfect for building real
apps, not just prototypes.
Angular 19 introduces useful features like Signals and new control flow
syntax that cut boilerplate and improve performance.</p>
</li>
<li>
<p><strong>NestJS</strong> is a structured backend framework with decorators, guards, and
strong support for things like JWTs and PostgreSQL—ideal for secure
authentication systems.</p>
</li>
<li>
<p><strong>PostgreSQL</strong> is a reliable, battle-tested relational database with great
tooling and support for user/session management.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Together, this stack gives you a clean, testable, and scalable
foundation—without gluing together a bunch of libraries yourself.</p>
</div>
</div>
<div class="sect2">
<h3 id="_what_youll_build">What You’ll Build</h3>
<div class="paragraph">
<p>Over this series, you’ll create a modular, full-stack authentication
boilerplate with:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A NestJS backend featuring JWT login and registration</p>
</li>
<li>
<p>A styled Angular frontend with auth forms and route guards</p>
</li>
<li>
<p>Token management, global error handling, and frontend state control</p>
</li>
<li>
<p>CI/CD pipelines, testing setup, and a containerized dev environment</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This isn’t a toy app—it’s a starting point for real projects.</p>
</div>
</div>
<div class="sect2">
<h3 id="_whats_new_in_angular_19">What’s New in Angular 19</h3>
<div class="paragraph">
<p>Angular 19 introduces major improvements that simplify frontend development
and reduce complexity:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Signals</strong> – A new reactive state primitive.
Think of it like <code>useState</code>, but built into Angular.
Great for managing form state and authentication status.</p>
</li>
<li>
<p><strong>Control Flow Syntax</strong> – <code>@if</code>, <code>@for</code>, and <code>@switch</code> clean up your
templates and reduce the need for verbose structural directives.</p>
</li>
<li>
<p><strong>Defer Blocks</strong> – Lazily load components based on app state, perfect for
gating authenticated vs. public views.</p>
</li>
<li>
<p><strong>Improved Change Detection</strong> – Smarter re-rendering out of the box for
better performance.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>We’ll use these features where they make sense—especially in the login and
registration flows—so you learn by doing.</p>
</div>
</div>
<div class="sect2">
<h3 id="_who_this_is_for">Who This Is For</h3>
<div class="paragraph">
<p>This series is for backend developers who want to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Understand modern Angular concepts without getting lost in frontend jargon</p>
</li>
<li>
<p>Build secure, token-based authentication flows using best practices</p>
</li>
<li>
<p>Deploy real full-stack apps with confidence</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You don’t need Angular experience.
If you know TypeScript, you’ll feel at home.</p>
</div>
</div>
<div class="sect2">
<h3 id="_tools_youll_need">Tools You’ll Need</h3>
<div class="sect3">
<h4 id="_required">Required</h4>
<div class="ulist">
<ul>
<li>
<p><strong>Node.js</strong> – Backend + Angular CLI</p>
</li>
<li>
<p><strong>NestJS CLI</strong> – Backend scaffolding</p>
</li>
<li>
<p><strong>Angular CLI</strong> – Frontend scaffolding</p>
</li>
<li>
<p><strong>PostgreSQL</strong> – Local dev database</p>
</li>
<li>
<p><strong>Git</strong> – Version control</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_optional_but_helpful">Optional (but helpful)</h4>
<div class="ulist">
<ul>
<li>
<p><strong>Postman</strong> – For testing APIs</p>
</li>
<li>
<p><strong>pgAdmin</strong> – For inspecting the database</p>
</li>
<li>
<p><strong>VS Code</strong> – With TypeScript extensions</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_getting_set_up">Getting Set Up</h3>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Install Node.js</strong><br>
<a href="https://nodejs.org" class="bare">https://nodejs.org</a></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">node -v
npm -v</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Install Angular and NestJS CLIs</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm install -g @angular/cli @nestjs/cli</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Install PostgreSQL</strong><br>
<a href="https://www.postgresql.org/download" class="bare">https://www.postgresql.org/download</a></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-sql" data-lang="sql">CREATE DATABASE auth_boilerplate;</code></pre>
</div>
</div>
</li>
<li>
<p><strong>Initialize Git Repo</strong></p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">git init</code></pre>
</div>
</div>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="_coming_up_next_part_2">Coming Up Next (Part 2)</h3>
<div class="paragraph">
<p>In Part 2, we’ll scaffold the NestJS backend, hook it up to PostgreSQL with
TypeORM, and implement JWT-based login and registration logic you can
actually ship.</p>
</div>
</div>
<div class="sect2">
<h3 id="_final_thoughts">Final Thoughts</h3>
<div class="paragraph">
<p>This series is about building something real—not another tutorial app you
toss out after reading.
Whether it’s for a SaaS product, side project, or production tool, having a
solid authentication foundation makes every other feature easier to build.</p>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Full-Stack Authentication Boilerplate: Angular + NestJS + PostgreSQL</title>
		<link>https://blog.lunatech.com//posts/2025-04-04-full-stack-authentication-boilerplate:-angular-+-nestjs-+-postgresql</link>
		
		<dc:creator><![CDATA[Jake Ortega]]></dc:creator>
        <pubDate>2025-04-04T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[angular]]></category>
                }
             {
            <category><![CDATA[nestjs]]></category>
                }
             {
            <category><![CDATA[postgresql]]></category>
                }
             {
            <category><![CDATA[typeorm]]></category>
                }
             {
            <category><![CDATA[jwt]]></category>
                }
             {
            <category><![CDATA[authentication]]></category>
                }
             {
            <category><![CDATA[frontend]]></category>
                }
             {
            <category><![CDATA[typescript]]></category>
                }
             {
            <category><![CDATA[nodejs]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-04-04-full-stack-authentication-boilerplate:-angular-+-nestjs-+-postgresql</guid>

					<description>
                        <![CDATA[ For backend developers who want to ship full-stack projects—without wrestling with frontend complexity.]]></description>
                    <content:encoded><![CDATA[
                    <h1 id="_a_practical_series_for_backend_developers_building_secure_full_stack_apps" class="sect0">A practical series for backend developers building secure full-stack apps</h1>
<div class="paragraph">
<p>For backend developers who want to ship full-stack projects—without wrestling with frontend complexity.</p>
</div>
<div class="paragraph">
<p>We’re building a <strong>full-stack authentication boilerplate</strong>—a reusable, modular codebase that gives you login, registration, route protection, token handling, and database integration out of the box. Clone it, customize it, and start building faster.</p>
</div>
<div class="sect2">
<h3 id="_why_this_stack">Why This Stack?</h3>
<div class="paragraph">
<p>We chose <strong>Angular 19</strong> and <strong>NestJS</strong> for a reason:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>TypeScript end-to-end</strong>: Write frontend and backend in the same language with consistent tooling.</p>
</li>
<li>
<p><strong>Angular 19</strong> introduces Signals and control flow syntax (<code>@if</code>, <code>@for</code>), simplifying state and UI logic.</p>
</li>
<li>
<p><strong>NestJS</strong> is structured, modular, and test-friendly—ideal for developers coming from Spring or .NET.</p>
</li>
<li>
<p><strong>PostgreSQL</strong> + <strong>TypeORM</strong> provide a robust relational layer with strong typing and migrations.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You <strong>could</strong> build this with React, Express, or MongoDB. But we picked this stack for its structure and scalability—great for teams or solo developers who want a solid foundation, not just flexibility.</p>
</div>
</div>
<div class="sect2">
<h3 id="_whats_in_the_series">What’s in the Series?</h3>
<div class="paragraph">
<p>Here’s the roadmap 👇</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-04-04-full-stack-authentication-boilerplate:-angular-+-nestjs-+-postgresql/roadmap.png" alt="Roadmap overview">
</div>
</div>
<div class="paragraph">
<p>Each post builds on the last, walking you through:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>✅ JWT login &amp; registration</p>
</li>
<li>
<p>✅ Angular route guards &amp; auth state</p>
</li>
<li>
<p>✅ NestJS modules, guards, and services</p>
</li>
<li>
<p>✅ PostgreSQL setup with TypeORM</p>
</li>
<li>
<p>✅ CI/CD, E2E tests with Playwright, and Docker deployment</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You don’t need prior Angular or NestJS experience—just TypeScript and backend fundamentals.</p>
</div>
</div>
<div class="sect2">
<h3 id="_why_this_series_exists">Why This Series Exists</h3>
<div class="paragraph">
<p>You don’t need another to-do app.</p>
</div>
<div class="paragraph">
<p>You need a <strong>working authentication foundation</strong>—something you can reuse, extend, and deploy. That’s what this series delivers, while helping you build real frontend + backend skills along the way.</p>
</div>
<div class="paragraph">
<p>Let’s build something you can actually ship.</p>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Mastering Typeclass Derivation with Scala 3</title>
		<link>https://blog.lunatech.com//posts/2025-03-07-typeclass-derivation</link>
		
		<dc:creator><![CDATA[Gustavo De Micheli]]></dc:creator>
        <pubDate>2025-03-07T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[scala]]></category>
                }
             {
            <category><![CDATA[typeclass]]></category>
                }
             {
            <category><![CDATA[metaprogramming]]></category>
                }
             {
            <category><![CDATA[we-know-scala]]></category>
                }
             {
            <category><![CDATA[scala-lujah]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-03-07-typeclass-derivation</guid>

					<description>
                        <![CDATA[ When learning about programming we stumble upon the concept of Polymorphism, and]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_polymorphism">Polymorphism</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When learning about programming we stumble upon the concept of Polymorphism, and
when learning something new I always wonder, why should we care? Besides getting
a new tool on our tool belt I think it&#8217;s important to understand what are we
getting from this new programming trick.</p>
</div>
<div class="paragraph">
<p>Polymorphism, from the Greek "having multiple forms", allows us to define and
implement a set of different algorithms using the same interface. This has the
benefit of lowering the complexity of our system from our client&#8217;s point of view.
By switching to another implementation, they don&#8217;t need to understand what changed
underneath, they just need to know that the interface is honored by another
implementation. And by lowering this complexity we lower the cognitive-load developers
need to have while using our API, making their code easier to maintain.</p>
</div>
<div class="paragraph">
<p>As far as I&#8217;m aware, there are at least 3 types of polymorphism:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Ad-Hoc</p>
</li>
<li>
<p>Parametric, and</p>
</li>
<li>
<p>Sub-type</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you come from a Object Oriented programming background you&#8217;ll recognize the last
one. Sub-type polymorphism is implemented by defining a parent class that
defines an API, and child classes implementing it. Then using a mechanism like
double-dispatch, a implementation is chosen based on the actual subclass being
instantiated:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">trait Shape:
    def area: Double

class Square(width: Double) extends Shape:
    override def area: Double = width * width

class Rectangle(width: Double, height: Double) extends Shape:
    override def area: Double = width * height

class Circle(radius: Double) extends Shape:
    override def area: Double = Math.pow(radius, 2) * Math.PI

val s1: Shape = new Circle(4)
val s2: Shape = new Rectangle(4, 2)

s1.area
s2.area</code></pre>
</div>
</div>
<div class="paragraph">
<p>Another type of polymorphism we can find in both Functional and Object Oriented
programming languages is Parametric polymorphism where we don&#8217;t necessarily
provide different implementations based on different types, but rather abstract
over some types:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">def identity[A](a: A): A = a

enum List[+A]:
    case Cons(head: A, tail: List[A]) extends List[A]
    case Nil extends List[Nothing]

    def map[B](fn: A =&gt; B): List[B] = this match
        case Cons(head, tail) =&gt; Cons(fn(head), tail.map(fn))
        case Nil =&gt; Nil</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>List</code> doesn&#8217;t care what&#8217;s containing, but its <code>map</code> method can easily work
for `Int`s, `String`s, and so on.</p>
</div>
<div class="paragraph">
<p>The last type of polymorphism we mentioned was <em>Ad-Hoc</em> polymorphism, which can
be defined as a "A system where functions or expressions are defined for specific
types". Let&#8217;s see how this gets implemented using Typeclasses.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_typeclasses">Typeclasses</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Typeclasses are a way to implement Ad-Hoc polymorphism with 2 significant properties:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Separate Definitions: For each relevant class, we define a separate instance of
a function or method (like <code>Show</code>, <code>Eq</code>, etc.) This similar to defining a
separate function for specific types.</p>
</li>
<li>
<p>Context-Dependent Selection: An implementation will be selected based on where
the typeclass is used.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In Scala, a Typeclass is implemented by defining 3 parts:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Interface: What functionality is the Typeclass offering.</p>
</li>
<li>
<p>Instances: How is that functionality implemented.</p>
</li>
<li>
<p>Usage: Where and how is that functionality used.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Let&#8217;s see a simple implementation of the <code>Show</code> Typeclass:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">// Interface
trait Show[A]:
    def show(a: A): String

// Instances
object Show:
    given Show[Int]     = (i: Int) =&gt; i.toString
    given Show[String]  = (s: String) =&gt; "'" + s + "'"
    given Show[Boolean] = (b: Boolean) =&gt; i.toString

// Usage
def log[A](a: A)(using s: Show[A]): Unit =
    println(s.show(a))</code></pre>
</div>
</div>
<div class="paragraph">
<p>An important detail of the Typeclass definition is that we use a Type Parameter
on it&#8217;s interface, instances, and usage.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_typeclass_derivation">Typeclass Derivation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>An interesting feature of Scala is that we can automatically generate the
instances of a Typeclass by implementing Typeclass Derivation code. This will
make the compiler generate instances at compile-time, making our Typeclass more
usable as we&#8217;ll shift the burden of implementation to our code instead of our
client&#8217;s code.</p>
</div>
<div class="paragraph">
<p>To derive instances for a Typeclass we need:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Tools to decompose complex types, such as case classes.</p>
</li>
<li>
<p>Tools to compose complex types from more simpler types.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>And one way we can approach implementing Derivation code is:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Think Recursively (Base vs. Iterative Case)</p>
</li>
<li>
<p>Implementing one Typeclass by implementing a simpler version first.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>On Scala 2 we&#8217;d use a library like <a href="https://github.com/milessabin/shapeless">Shapeless</a> or
<a href="https://github.com/softwaremill/magnolia">Magnolia</a> to compose and decompose complex
types. In Scala 3 these features are backed in the language.</p>
</div>
<div class="paragraph">
<p><a href="https://docs.scala-lang.org/scala3/reference/contextual/derivation.html#mirror-1">Mirrors</a> provide
typelevel information about types being derived, with similar features as <em>HList</em> and
<em>Coproduct</em> in a single abstraction.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">import scala.collection.AbstractIterable
import scala.compiletime.{erasedValue, error, summonInline}
import scala.deriving.*

// Interface
trait Show[A]:
    def show(a: A): String

// Instances
object Show:
    given Show[Int]     = (i: Int) =&gt; i.toString
    given Show[String]  = (s: String) =&gt; "'" + s + "'"
    given Show[Boolean] = (b: Boolean) =&gt; i.toString

    def iterable[T](p: T): Iterable[Any] = new AbstractIterable[Any]:
        def iterator: Iterator[Any] = p.asInstanceOf[Product].productIterator

    def showProduct[T](p: Mirror.ProductOf[T], elems: =&gt; List[Show[?]]): Show[T] =
        new Show[T]:
            def show(a: A): String =
                iterable(x).lazyZip(elems).map { case (i, s) =&gt; s.show(i) }.mkString(",")

    inline def derived[A](using m: Mirror.ProductOf[A]): Show[A] =
        lazy val elemInstances = summonInstances[T, m.MirroredElemTypes]
        showProduct(m, elemInstances)

    inline def summonInstances[T, Elems &lt;: Tuple]: List[Show[?]] =
        inline erasedValue[Elems] match
            case _: (elem *: elems) =&gt; deriveOrSummon[T, elem] :: summonInstances[T, elems]
            case _: EmptyTuple =&gt; Nil

    inline def deriveOrSummon[T, Elem]: Show[Elem] =
        inline erasedValue[Elem] match
            case _: T =&gt; deriveRec[T, Elem]
            case _    =&gt; summonInline[Show[Elem]]

    inline def deriveRec[T, Elem]: Show[Elem] =
        inline erasedValue[T] match
            case _: Elem =&gt; error("infinite recursive derivation")
            case _       =&gt; Show.derived[Elem](using summonInline[Mirror.Of[Elem]]) // recursive derivation</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is a simplified example of a Typeclass Derivation for the <code>Show</code> Typeclass.
For a more thorough example with a more detailed explanation, I cannot recommend
<a href="https://docs.scala-lang.org/scala3/reference/contextual/derivation.html">Type Class Derivation</a> enough.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>The Scala effect: Java’s Evolution Inspired by Scala</title>
		<link>https://blog.lunatech.com//posts/2025-02-28-the-scala-effect</link>
		
		<dc:creator><![CDATA[]]></dc:creator>
        <pubDate>2025-03-04T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[jvm]]></category>
                }
             {
            <category><![CDATA[scala]]></category>
                }
             {
            <category><![CDATA[java]]></category>
                }
             {
            <category><![CDATA[java8]]></category>
                }
             {
            <category><![CDATA[java11]]></category>
                }
             {
            <category><![CDATA[java17]]></category>
                }
             {
            <category><![CDATA[java21]]></category>
                }
             {
            <category><![CDATA[we-know-scala]]></category>
                }
             {
            <category><![CDATA[scala-lujah]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-02-28-the-scala-effect</guid>

					<description>
                        <![CDATA[ Since its inception, Java has been one of the most widely used programming languages,]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_contents">Contents</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Since its inception, Java has been one of the most widely used programming languages,
known for its stability and enterprise adoption.
However, as modern software development demands more expressive and concise code,
Java has often looked to other languages for inspiration.
One of its biggest influences has been Scala—a language that brought functional programming,
immutability, and expressive syntax to the JVM.</p>
</div>
<div class="paragraph">
<p>Over the years, Java has steadily incorporated many features that were first introduced in Scala,
from lambda expressions and pattern matching to records and data-oriented programming.
In this article, we’ll explore how Java has evolved by adopting concepts from Scala,
breaking down the changes version by version. We&#8217;ll also see some examples,
to see each language&#8217;s unique approach, while pointing out some key differences.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_java_8">Java 8</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_stream_api">Stream API</h3>
<div class="paragraph">
<p>I don&#8217;t think I need to introduce many of the readers to the Stream API, born in Java 8.
It is also well known, how it basically changed the game on how you approach operations on collections.
What might be a bit less known is the fact, that this feature is a big step towards functional programming,
since the API promotes functional paradigms, such as immutability, pure functions, higher level functions.
Exploring those paradigms could use a talk in itself, so the below example is rather to show,
from a developer experience perspective how easy it is to do multiple, small operations on a collection,
with the new API compered to the old way.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">def getNamesOfMammals(animals: List[Animal]): List[String] =
  animals
    .filter(_.classification == "mammal")
    .map(_.name)</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">private List&lt;String&gt; getNamesOfMammals(List&lt;Animal&gt; animals) {
    List&lt;String&gt; names = new ArrayList&lt;&gt;();

    for (Animal animal: animals) {
        if (animal.classification.equals("mammal")) {
            names.add(animal.name);
        }
    }

    return names;
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">private List&lt;String&gt; getNamesOfMammals(List&lt;Animal&gt; animals) {
    return animals
        .stream()
        .filter(animal -&gt; animal.classification.equals("mammal"))
        .map(animal -&gt; animal.name)
        .toList();
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="paragraph">
<p>It is worth to note, that the above example is nice, and already a huge step in the right direction,
when it comes to streaming data processing, java still lacks support for a lot of major operations (fold, sliding windows).</p>
</div>
</div>
<div class="sect2">
<h3 id="_optional">Optional</h3>
<div class="paragraph">
<p>Safety first! Especially when it comes to nulls, and java. <code>Option</code> is a core part of the Scala language,
making nullable data a breeze to work with, through great support for operations, and branchless behaviour definition.
Java intends to implement some of that functionality with the <code>Optional</code> class. Just like in the streams' case,
scala still offers more flexibility and more defined developer options, when it comes to potentially missing data (e.g.: <code>exists</code>, <code>forall</code>).
The example illustrates the boilerplate needed to handle nested nullable structures,
and the positive steps java already took in the right direction.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">case class Wing(length: Int, fact: Option[String])
case class Animal(name: String, wing: Option[Wing])

def printSafeInterestingWingFacts(animals: List[Animal]) =
  animals.foreach { animal =&gt; println(s"""${animal.name}: ${
    animal.wing
      .flatMap(_.fact)
      .getOrElse("no interesting wing fact :(")}""")}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">class Wing{public Integer length; public String fact;}
class Animal{public String name; public Wing wing;}

private void printInterestingWingFacts(List&lt;Animal&gt; animals) {
    for (Animal animal: animals) {
        if (animal.wing != null) {
            if (animal.wing.fact != null) {
                System.out.printf("%s: %s%n", animal.name, animal.wing.fact);
            } else {
                System.out.printf("%s: no interesting wing fact :(%n", animal.name);
            }
        } else {
            System.out.printf("%s: no interesting wing fact :(%n", animal.name);
        }
    }
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">class Wing{public Integer length; public Optional&lt;String&gt; fact;}
class Animal{public String name; public Optional&lt;Wing&gt; wing;}

private void printSafeInterestingWingFacts(List&lt;Animal&gt; animals) {
    animals.forEach(animal -&gt; {
        System.out.printf("%s: %s%n", animal.name, animal.wing
            .flatMap(wing -&gt; wing.fact)
            .orElse("no interesting wing fact :(%n"));
    });
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_functional_interfaces_lambdas">Functional interfaces (lambdas)</h3>
<div class="paragraph">
<p>One of the key prerequisites of having support for all these functional paradigms, is to be able to pass functions as arguments.
Java implements this concept via so-called functional interfaces. A functional interface, is an interface,
with only one method declared. Java 8 also makes it easier to use these interfaces with the lambda syntax.
With the lambda syntax you can pass lambda functions as arguments, and the compiler will be able to interpret it,
as the needed interface.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">def chainEvenNumbers(numbers: List[Int]): String =
  numbers
  .filter(n =&gt; n % 2 == 0)
  .map(n =&gt; n.toString)
  .reduce{case (n1, n2) =&gt; n1 + n2}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">String chainEvenNumbers(List&lt;Integer&gt; numbers) {
    Predicate&lt;Integer&gt; predicate = new Predicate&lt;&gt;() {
        @Override
        public boolean test(Integer integer) {
            return integer % 2 == 0;
        }
    };

    Function&lt;Integer, String&gt; mapper = new Function&lt;&gt;() {
        @Override
        public String apply(Integer integer) {
            return integer.toString();
        }
    };

    BinaryOperator&lt;String&gt; accumulator = new BinaryOperator&lt;&gt;() {
        @Override
        public String apply(String s, String s2) {
            return s + s2;
        }
    };

    return numbers
        .stream()
        .filter(predicate)
        .map(mapper)
        .reduce("", accumulator);
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">String chainEvenNumbers(List&lt;Integer&gt; numbers) {
    return numbers
        .stream()
        .filter(i -&gt; i % 2 == 0)
        .map(Object::toString)
        .reduce("", (s, s2) -&gt; s + s2);
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_java_11">Java 11</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Java 11&#8217;s main features fall outside of this article&#8217;s scope, since they are not directly influenced by Scala,
nor resemble existing Scala features. I would like to mention however a couple small additions,
mainly in the area of scripting, and writing / running fast, without overhead.
OVer the years a good argument for learning Scala (or against learning java, really) was that for a beginner,
the learning curve might be steep, and writing small code snippets is not really possible.
On top of that, while it scales up excellent, it is not really ideal for small projects.
The following additions you can argue how much they were inspired by Scala actually (I wouldn&#8217;t argue against it either),
but one thing is not arguable: Scala was always ahead in these topics, and with 11, Java is now one step closer.</p>
</div>
<div class="sect2">
<h3 id="_collectionof_factory_method_java_9"><code><em>&lt;Collection&gt;</em>::of</code> factory method (Java 9)</h3>
<div class="paragraph">
<p>No more dubious initialization, and element adding after, with Java 11 now most of the commonly used collections receive
the <code>::of</code> factory method, where you can quickly create a new immutable instance, with a number of initial elements.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">val l: List[Int] = List(1, 2, 3, 4, 5)</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">List&lt;Integer&gt; l = new ArrayList&lt;&gt;();

l.add(1);
l.add(2);
l.add(3);
l.add(4);
l.add(5);</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">List&lt;Integer&gt; l = List.of(1, 2, 3, 4, 5);</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_introduction_of_jshell_java_repl_java_9">Introduction of <code><em>jshell</em></code> (java REPL) (Java 9)</h3>
<div class="paragraph">
<p>Huge step towards scripting, but also really important for bigger projects. The presence of the jshell
is equally amazing for absolute beginners, as well as seasoned developers. It could be used in various ways,
from writing quick <em>"hello world"</em> code to quickly test out more serious code in a bigger production environment.
The java REPL is not yet that advanced as the Scala counterpart, but this long overdue feature
is again making the language a bit more consumable.</p>
</div>
</div>
<div class="sect2">
<h3 id="_addition_of_var_keyword_java_11">Addition of var keyword (Java 11)</h3>
<div class="paragraph">
<p>If it was not a 100% clear what does it mean, when we talk about steep learning curve for beginners,
or challenges to test out code segment quickly in a bigger environment,
having to quickly write a code like this (in both cases) hopefully explains it:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">void testStateAndTranslator() {
    InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState state = nimbus.getState();
    assert state == expectedState;
    RefreshAuthorizationPolicyProtocolServerSideTranslatorPB translator = hadoop.getTranslator();
    assert translator == expectedTranslator;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now this is a test, where you would most likely get some autocorrection, but imagine the nightmare typing these in the REPL!
Luckily if you want to quicly test out something like this, sice java 11 it would only look like something like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">jshell&gt; var state = nimbus.getState()
state ==&gt; InternalFrameInternalFrameTitlePaneInternalFrameT ... owNotFocusedState@1a86f2f1

jshell&gt; state.testStuff()
Stuff works!</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_launch_single_file_java_11">Launch single file (Java 11)</h3>
<div class="paragraph">
<p>This is all great so far, but what if you want to write some code quickly to generate input, or want to process a file?
You wouldn&#8217;t want to include that file in your project, and definitely don&#8217;t want to recompile every time you tweak that
<code>println</code> statement. With Java 11, you get another benefit which points java in the scripting direction.
You can run single java files, without associating it to a project, or even without precompiling it.
In fact you can include a <code>she-bang</code> line, and run it as a shell script!</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">❯ javac HelloWorldJava8.java
❯ java HelloWorldJava8
Hello World!
❯ java HelloWorldJava11.java
Hello World!
❯ ./HelloWorldJava11Shell.java
Hello World!</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_java_17">Java 17</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_switch_expressions_java_14">Switch expressions (Java 14)</h3>
<div class="paragraph">
<p>Switch expressions' functionality is still limited to the same restrictions as before
(we are going to talk about these restrictions later), but it got a nice facelift,
where you can leave a lot of boilerplate code behind!</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">def kindergartenToString(number: Int): String =
  number match {
  case 1 =&gt; "1"
  case 2 =&gt; "2"
  case _ =&gt; "cannot count until that"
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">private String kindergartenToString(Integer number) {
    String result;
    switch (number) {
        case 1:
            result = "1";
            break;
        case 2:
            result = "2";
            break;
        default:
            result = "cannot count until that";
    };

    return result;
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">private String kindergartenToString(Integer number) {
    return switch (number) {
        case 1 -&gt; "1";
        case 2 -&gt; "2";
        default -&gt; "cannot count until that";
    };
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_text_blocks_java_15">Text blocks (Java 15)</h3>
<div class="paragraph">
<p>Another long overdue feature, where you wonder, why exactly did we need to wait until Java 15 for that?</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">var sql =
  """
    |SELECT
    |  name,
    |  salary,
    |  title
    |FROM
    |  employees
    |WHERE
    |  age &lt; 25
    |  AND title in (
    |    SELECT
    |      summary
    |    FROM
    |      jobs
    |  )
    |""".stripMarging</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">String sql = "SELECT\n" +
            "  name,\n" +
            "  salary,\n" +
            "  title\n" +
            "FROM\n" +
            "  employees\n" +
            "WHERE\n" +
            "  age &lt; 25\n" +
            "  AND title in (\n" +
            "    SELECT\n" +
            "      summary\n" +
            "    FROM\n" +
            "      jobs\n" +
            "  )";</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">String sql = """
            SELECT
              name,
              salary,
              title
            FROM
              employees
            WHERE
              age &lt; 25
              AND title in (
                SELECT
                  summary
                FROM
                  jobs
              )""";</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_pattern_matching_instanceof_java_16">Pattern matching instanceof (Java 16)</h3>
<div class="paragraph">
<p>You can argue if this in itself is a huge step or not, but this definitely set the table, for what&#8217;s to come with Java 21.
And not having to cast (although it is 100% safe, already from context) by hand every time,
and having to have either multiple casts, or nested branches is already a big step, but let the code speak for itself.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">def callIfPositiveInt(any: Any): Unit =
  any match {
    case i: Int =&gt; i.someMethodOnInt()
  }</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">void callIfPositiveIntImpl1(Object object) {
    if (object instanceof Integer) {
        Integer i = (Integer) object;

        if (i &gt; 0) {
            i.someMethodOnInteger();
        }
    }
}

void callIfPositiveIntImpl2(Object object) {
    if (object instanceof Integer &amp;&amp; ((Integer) object) &gt; 0) {
        Integer i = (Integer) object;
        i.someMethodOnInteger();
    }
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">void callIfPositiveInt(Object object) {
    if (object instanceof Integer i &amp;&amp; i &gt; 0) {
        i.someMethodOnInteger();
    }
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_record_classes_java_16">Record classes (Java 16)</h3>
<div class="paragraph">
<p>Record classes are a new type declaration, that allows you to compactly define immutable data classes.
They are intended to be transparent carriers of their shallowly immutable data.</p>
</div>
<div class="paragraph">
<p>They resemble the well known <code>case class</code> in Scala. There&#8217;s no such thing as "same" between two languages,
so it goes without saying that they have (on top of the many similarities) some differences.
Exactly discovering all the similarities and differences is outside of the scope of this article,
but from a developer experience perspective, being able to write compact code that speaks for itself
is the same for both.</p>
</div>
<div class="paragraph">
<p>Records are going to be even more powerful in Java 21, paired with pattern matching concepts.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">case class Point(x: Int, y: Int)


val point = Point(1, 2)
val x = point.x
val y = point.y
val hashCode = point.hashCode
val s = point.toString // "Point[x=1, y=2]"

assert(point == Point(1, 2))
assert(!(point == Point(2, 2)))</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">class Point {
    private final Integer x;
    private final Integer y;

    public Point(Integer x, Integer y) {
        this.x = x;
        this.y = y;
    }

    public Integer x() {
        return x;
    }

    public Integer y() {
        return y;
    }

    @Override
    public String toString() {
        return String.format("Point[x=%d, y=%d]", x, y);
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (!(object instanceof Point point)) return false;
        return Objects.equals(x, point.x) &amp;&amp; Objects.equals(y, point.y);
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}


Point point = new Point(1, 2);
Integer x = point.x();
Integer y = point.y();
int hashCode = point.hashCode();
String s = point.toString(); // "Point[x=1, y=2]"
assert point.equals(new Point(1, 2));
assert !point.equals(new Point(2, 2));</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">record Point(Integer x, Integer y) {}


Point point = new Point(1, 2);
Integer x = point.x();
Integer y = point.y();
int hashCode = point.hashCode();
String s = point.toString(); // "Point[x=1, y=2]"
assert point.equals(new Point(1, 2));
assert !point.equals(new Point(2, 2));</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_sealed_interfacesclasses_java_17">Sealed interfaces/classes (Java 17)</h3>
<div class="paragraph">
<p>With Scala&#8217;s language focus not just leverages, but was built on <em>pattern matching</em>,
having an option to control your class hierarchy is essential. Hence sealed traits (interfaces)
are essential part of scala. With it you can have fine grained control of the class hierarchy,
and have guarantees for all possible subclasses, making pattern matching even more powerful.
With the power of such features catching java&#8217;s attention, it had to adapt some of the concepts as well.</p>
</div>
<div class="paragraph">
<p>With sealed interfaces it is possible to have exact control over your class subclasses that can implement your class / interface.
With having switch expression coming only in java 21, with java 17 most of the gains is
having all the control over your class hierarchy, enabling you to enforce design principles,
and prevent unauthorized extensions.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">sealed interface Animal permits Dog, Cat {}
final class Dog implements Animal {}
final class Cat implements Animal {}
final class Bird implements Animal {}

"‘Bird' is not allowed in the sealed hierarchy"</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_java_21">Java 21</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_sequencedcollection_interface"><code>SequencedCollection</code> interface</h3>
<div class="paragraph">
<p>Before Java 21 accessing elements in order was not just not straight forward, but some brave people might call it chaos.
With some of the types not having any method to access sequential elements (like <code>getFirst</code>, <code>getLast</code>, <code>reversed</code>),
while others having the same, on top of some these' supertypes / subtypes having methods for that, while others did not.
And even the ones having methods, had separate means of calling those. In short: chaos.</p>
</div>
<div class="paragraph">
<p>With Java 21, the collections implementing sequential elements have to implement the <code>SequentialCollection</code> interface,
making the existence of these methods obvious, and unified.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">def doStuff(
  list: List[Int],
  deque: ArrayDeque[Int],
  sortedSet: SortedSet[Int],
  linkedHashSet: LinkedHashSet[Int]
) = {
  var i = 0
  // get first
  i = list.head
  i = deque.head
  i = sortedSet.head
  i = linkedHashSet.head
  // get last
  i = list.last
  i = deque.last
  i = sortedSet.last
  i = linkedHashSet.last
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">void doStuff(
    List&lt;Integer&gt; list,
    Deque&lt;Integer&gt; deque,
    SortedSet&lt;Integer&gt; sortedSet,
    LinkedHashSet&lt;Integer&gt; linkedHashSet
) {
    Integer i;
    // get first
    i = list.get(0);
    i = deque.getFirst();
    i = sortedSet.first();
    i = linkedHashSet.iterator().next();
    // get last
    i = list.get(list.size() - 1);
    i = deque.getLast();
    i = sortedSet.last();
    // i = linkedHashSet.? missing
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">void doStuff2(
    List&lt;Integer&gt; list,
    Deque&lt;Integer&gt; deque,
    SortedSet&lt;Integer&gt; sortedSet,
    LinkedHashSet&lt;Integer&gt; linkedHashSet
) {
    Integer i;
    // get first
    i = list.getFirst();
    i = deque.getFirst();
    i = sortedSet.getFirst();
    i = linkedHashSet.getFirst();
    // get last
    i = list.getLast();
    i = deque.getLast();
    i = sortedSet.getLast();
    i = linkedHashSet.getLast();
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_pattern_matching_switch">Pattern matching switch</h3>
<div class="paragraph">
<p>Switch expressions were a nice syntactic sugar, but functionality wise they didn&#8217;t come with anything new.
You could still only use primitive types, Strings, or enums, and were only able to match on the concrete value of the input.
With java 21 all that changed, and you can use switch expressions with any types.
In order to actually take advantage of this of course, a lot of new patterns were introduced on top of the value match.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>null pattern<br>
In previous versions if the value was <code>null</code> inside the <code>switch</code>, it would always throw  <code>NullPointerException</code>.
With the new null pattern these exceptions can be caught.</p>
</li>
<li>
<p>type pattern<br>
You can now pattern match for the types. Just like with the pattern matching <code>instanceof</code>,
you can use the new type without any casting necessary.</p>
</li>
<li>
<p>guarded patterns<br>
You can define additional conditions for you patterns. This very well corresponds with the syntax,
previously seen with <code>instanceof</code>, where the matched arguments can already be used as a concrete type in the guards.</p>
</li>
<li>
<p>record deconstruction<br>
You can not only match on <code>records</code> similarly to the type pattern, but it is now possible to deconstruct nested structures,
and match on nested types as well. You can also use the concrete types of these nested values.
That is very powerful with deeply nested structures, where you don&#8217;t need to access a very deep value by hand.<br>
Note, that this new record deconstruction also works with the <code>instanceof</code> operator.</p>
</li>
<li>
<p>sealed class exhaustion<br>
Pattern matching switch is, where the most powerful feature of sealed classes / interfaces come to light.
Because the compiler knows exactly which classes can implement a sealed class, if the input of the switch is a sealed class,
you don&#8217;t need to define a <code>default</code> case, since the compiler is able to tell if the switch is exhaustive or not.
That way, previously existing bugs, of not updating a switch, when e.g. the domain changes are a thing in the past,
because with this new addition the compiler will force you to.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>There is no point of bringing an old example for this, since it is so different from the core,
you would simply look for another approach in previous java versions.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scala</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">case class Wing(length: Int, fact: Option[String])

sealed trait Animal

case class Dog() extends Animal
case class Cat() extends Animal
case class Bird(birdType: String, wing: Wing) extends Animal

def getWingStatus(animal: Animal): String = animal match {
  case null =&gt; "no animal provided"
  case Dog() =&gt; "dogs don't have wings"
  case Cat() =&gt; "cats don't have wings"
  case Bird(_, Wing(_, fact)) if fact.isDefined =&gt; s"interesting fact: ${fact.get}"
  case Bird(_, Wing(_, Some(fact))) =&gt;
    s"interesting fact: ${fact}"
  case Bird(birdType, Wing(length, _)) =&gt;
    s"$birdType has $length long wings"
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">record Wing(Integer length, Optional&lt;String&gt; fact) {}

sealed interface Animal permits Dog, Cat, Bird {}

final class Dog implements Animal {}
final class Cat implements Animal {}
record Bird(String birdType, Wing wing) implements Animal {}

private String getWingStatus(Animal animal) {
    return switch (animal) {
        case null -&gt; "no animal provided";
        case Dog ignored -&gt; "dogs don't have wings";
        case Cat ignored -&gt; "cats don't have wings";
        case Bird(String birdType, Wing(Integer length, Optional&lt;String&gt; fact))
            when fact.isPresent() -&gt; "interesting fact: " + fact.get();
        case Bird(String birdType, Wing(Integer length, Optional&lt;String&gt; fact)) -&gt;
            String.format("%s has %d long wings", birdType, length);
    };
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="paragraph">
<p>You can see, how it is pretty similar now in that exact case. However one must note,
that while this is the new best thing in java, that is just the tip of the iceberg in Scala.</p>
</div>
<div class="paragraph">
<p>You can already see an example for that above, where (right before the guard pattern) the type pattern,
and the literal value pattern is mixed. First the the type <code>Bird</code> is matched,
then the record deconstructed, in a way that it will only match, if the wingfact is present.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_beyond">Beyond</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_unnamed_variables_java_22">Unnamed variables (Java 22)</h3>
<div class="paragraph">
<p>A minor improvement in developer experience is introducing unnamed variables.
If you take a look at the previous example for pattern matching, you would notice,
that although the example now looks pretty similar, in case of java you still had to give some name to the variables,
even if you are not using them later on. With the introduction of unnamed variables you can use <code>_</code> as the identifier,
and you can reuse it as many times as you&#8217;d like, and not be able to reference it later.
So it does not clutter up your scope, nor can it overshadow an outside variable by accident.
In short it doesn&#8217;t just signals the implementor&#8217;s intention, but enforces it as well,
making the code safer, and more obvious to read in the future.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">private String getWingStatus(Animal animal) {
    return switch (animal) {
        case null -&gt; "no animal provided";
        case Dog _ -&gt; "dogs don't have wings";
        case Cat _ -&gt; "cats don't have wings";
        case Bird(String _, Wing(Integer _, Optional&lt;String&gt; fact))
            when fact.isPresent() -&gt; "interesting fact: " + fact.get();
        case Bird(String birdType, Wing(Integer length, Optional&lt;String&gt; _)) -&gt;
            String.format("%s has %d long wings", birdType, length);
    };
}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_unnamed_classes_java_22">Unnamed classes (Java 22)</h3>
<div class="paragraph">
<p>With previous versions already enabling running java as a single file, or even as a script,
the need for defining an exact main class is fading. This new feature leverages that thought,
and lets the user create java files without extra boilerplate.</p>
</div>
<div class="openblock scrollable">
<div class="content">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Java (old)</th>
<th class="tableblock halign-left valign-top">Java (new)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">public class HelloWorldJava8 {
    public static void main(String[] args) {
	    System.out.println("Hello World");
    }
}</code></pre>
</div>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">void main() {
    System.out.println("Hello World");
}</code></pre>
</div>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="paragraph">
<p>This makes the learning curve much easier for a newcomer, but also opens the door to even easier scripting in the future.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_closing_thoughts">Closing thoughts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If now, you feel like Scala is bad, because Java adopted its best features I failed.
If you feel like Java is bad, because it lacks a lot of features Scala has, I also failed.
If you feel like Java is excellent, because it can adopt in an environment, it&#8217;s maybe not that familiar,
and you feel like Scala is excellent, because it can leverage a familiar environment to the fullest,
only then I have truly succeeded.</p>
</div>
<div class="paragraph">
<p>What we need to understand, is the goal of Scala, and Java are two very different things.
Scala is a functional programming language, so the language and its whole ecosystem is designed around that fact,
while java&#8217;s main focus lies rather elsewhere.</p>
</div>
<div class="paragraph">
<p>The fact, that Java recognizes the value in a lot of functional paradigms shows the modern thinking of its maintainers,
and projects a bright future ahead.</p>
</div>
<div class="paragraph">
<p>The fact, that these paradigms are existing, and also well implemented
(even well enough for the <em>old bigbrother</em> java) shows great design from the creators of Scala.</p>
</div>
<div class="paragraph">
<p>Java and Scala, while distinct in their philosophies, have carved out a shared space within the JVM ecosystem,
proving that innovation and tradition can coexist, complement,
and even elevate each other, hence elevate modern software development.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>SBT: More than a Build Tool</title>
		<link>https://blog.lunatech.com//posts/2025-02-21-sbt-more-than-a-build-tool</link>
		
		<dc:creator><![CDATA[George]]></dc:creator>
        <pubDate>2025-02-21T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[sbt]]></category>
                }
             {
            <category><![CDATA[build-tool]]></category>
                }
             {
            <category><![CDATA[scala]]></category>
                }
             {
            <category><![CDATA[jvm]]></category>
                }
             {
            <category><![CDATA[we-know-scala]]></category>
                }
             {
            <category><![CDATA[scala-lujah]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-02-21-sbt-more-than-a-build-tool</guid>

					<description>
                        <![CDATA[ Scala Build Tool (SBT) is widely known for compiling, testing, and packaging Scala projects. However, its design as an extensible, programmable tool opens doors to uses beyond traditional build automation. Let's explore SBT's additional functionalities and practical applications.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Scala Build Tool (SBT) is widely known for compiling, testing, and packaging Scala projects. However, its design as an extensible, programmable tool opens doors to uses beyond traditional build automation. Let&#8217;s explore SBT&#8217;s additional functionalities and practical applications.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_sbt_a_brief_overview">SBT: A Brief Overview</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_what_is_sbt">What is SBT?</h3>
<div class="paragraph">
<p>SBT (Scala Build Tool) is the de facto build tool for Scala projects. It&#8217;s an open-source build tool written in Scala that provides a Domain-Specific Language (DSL) for describing build configurations. SBT offers interactive capabilities, incremental compilation, and continuous compilation features. It uses Scala code for build definitions, allowing developers to leverage the full power of the Scala language in their build processes.</p>
</div>
</div>
<div class="sect2">
<h3 id="_sbt_vs_traditional_build_tools">SBT vs Traditional Build Tools</h3>
<div class="paragraph">
<p>SBT is specifically designed for Scala projects, with deep integration into the Scala ecosystem. While it can handle Java code within Scala projects, it&#8217;s not typically used for pure Java projects where tools like Maven and Gradle are more appropriate.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_practical_applications_of_sbt">Practical Applications of SBT</h2>
<div class="sectionbody">
<div class="sect3">
<h4 id="_simple_configuration">Simple Configuration</h4>
<div class="paragraph">
<p>SBT follows "convention over configuration" principles. For basic Scala projects, you might only need a few lines in your <code>build.sbt</code> file.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">name := "my-project"
version := "1.0"
scalaVersion := "2.13.10"</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_scala_based_build_definition">Scala-Based Build Definition</h4>
<div class="paragraph">
<p>Unlike XML-based build tools, SBT lets you write your build configuration in Scala. This means you can use variables, functions, and even complex logic in your build definitions, making them more maintainable and powerful.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">val commonSettings = Seq(
  organization := "com.example",
  version := "1.0",
  scalaVersion := "2.13.10"
)

lazy val core = (project in file("core"))
  .settings(commonSettings)
  .settings(
    name := "my-core-project",
    libraryDependencies += "org.typelevel" %% "cats-core" % "2.9.0"
  )</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_incremental_compilation">Incremental Compilation</h4>
<div class="paragraph">
<p>SBT tracks dependencies between your source files and only recompiles what&#8217;s necessary. When you change a file, SBT analyzes its dependencies and recompiles only affected files, significantly reducing build times.</p>
</div>
</div>
<div class="sect3">
<h4 id="_library_management">Library Management</h4>
<div class="paragraph">
<p>Using Coursier as its dependency resolver, SBT efficiently handles library dependencies, resolving and downloading them from repositories. It manages transitive dependencies and version conflicts automatically.</p>
</div>
</div>
<div class="sect3">
<h4 id="_continuous_compilation">Continuous Compilation</h4>
<div class="paragraph">
<p>With the <code>~</code> command prefix, SBT watches your source files and automatically recompiles when changes are detected. This creates a rapid development cycle, perfect for interactive development.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">// Watch and recompile
$ sbt "~compile"

// Watch and run tests
$ sbt "~test"

// Watch specific test
$ sbt "~testOnly com.example.MySpec"</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_mixed_scalajava_support">Mixed Scala/Java Support</h4>
<div class="paragraph">
<p>SBT seamlessly handles projects containing both Scala and Java code, automatically detecting and compiling both languages while maintaining proper dependency ordering.</p>
</div>
</div>
<div class="sect3">
<h4 id="_testing_framework_integration">Testing Framework Integration</h4>
<div class="paragraph">
<p>Built-in support for major Scala testing frameworks means you can run tests directly from SBT. It integrates with ScalaTest, specs2, and ScalaCheck out of the box, with plugin support for JUnit.</p>
</div>
</div>
<div class="sect3">
<h4 id="_interactive_scala_repl">Interactive Scala REPL</h4>
<div class="paragraph">
<p>Launch a Scala REPL session with your project&#8217;s classes and dependencies already loaded, perfect for exploring and testing code interactively.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">// In your project
case class User(name: String, age: Int)
class UserService {
  def greet(user: User) = s"Hello, ${user.name}!"
}

// In the REPL (after running 'sbt console')
scala&gt; val user = User("Alice", 25)
user: User = User(Alice,25)

scala&gt; val service = new UserService
service: UserService = UserService@1234abcd

scala&gt; service.greet(user)
res0: String = Hello, Alice!</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_project_modularization">Project Modularization</h4>
<div class="paragraph">
<p>Break down complex projects into manageable sub-projects, each with its own dependencies and configurations, while maintaining build coordination across the entire project.</p>
</div>
</div>
<div class="sect3">
<h4 id="_external_project_dependencies">External Project Dependencies</h4>
<div class="paragraph">
<p>Reference other Git repositories directly as dependencies, enabling seamless integration with external projects and custom forks of libraries.</p>
</div>
</div>
<div class="sect3">
<h4 id="_parallel_execution">Parallel Execution</h4>
<div class="paragraph">
<p>Speed up builds and tests by running independent tasks in parallel, taking advantage of multiple CPU cores for faster build times. By default SBT runs tasks in parallel and tests in sequence. You can change this behavior by configuring the build.sbt file by either enablig test parallelism and adjusting the parallel execution settings, such as limiting the number of cores used for example.</p>
</div>
</div>
<div class="sect2">
<h3 id="_beyond_build_tool_features">Beyond Build Tool Features</h3>
<div class="sect3">
<h4 id="_custom_task_creation">Custom Task Creation</h4>
<div class="paragraph">
<p>SBT allows you to define custom tasks for any purpose - from deploying applications to generating documentation. You can create tasks that integrate with external services, process data, or automate any development workflow.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">// Define individual tasks
lazy val startDb = taskKey[Unit]("Starts the database")
startDb := {
  "docker-compose up -d postgres".!
}

lazy val runMigrations = taskKey[Unit]("Runs database migrations")
runMigrations := Def.sequential(
  startDb,                // Start database first
  flywayClean,           // Clean database schema
  flywayMigrate          // Run Flyway migrations
).value</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_development_workflow_automation">Development Workflow Automation</h4>
<div class="paragraph">
<p>Use SBT as a complete development environment orchestrator. Create custom commands to start databases, mock services, or set up entire development environments with a single command.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">// Combine previously defined tasks into a workflow
lazy val startLocalEnv = taskKey[Unit]("Start local development environment")
startLocalEnv := Def.sequential(
  runMigrations,         // Run database migrations
  (Compile / run)        // Finally start the application
).value</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">// Use it with:
&gt; sbt startLocalEnv  // Executes all tasks in sequence</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_code_generation">Code Generation</h4>
<div class="paragraph">
<p>Leverage SBT&#8217;s source generators to automatically create code, such as generating case classes from database schemas, creating TypeScript definitions from Scala classes, or producing API documentation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_database_migration">Database Migration</h4>
<div class="paragraph">
<p>Through plugins like Flyway or Slick-migration, SBT can manage database schemas and migrations, making it a powerful tool for database version control and deployment.</p>
</div>
<div class="paragraph">
<p>Using the SBT Flyway plugin:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">// In plugins.sbt
addSbtPlugin("io.github.davidmweber" % "flyway-sbt" % "7.4.0")

// In build.sbt
flywayConfigFiles := Seq("flyway-e2e.conf")</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">&gt; sbt flywayMigrate    // Using the SBT plugin</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_documentation_generation">Documentation Generation</h4>
<div class="paragraph">
<p>Beyond API docs, SBT can generate various types of documentation, from project websites to technical specifications, using plugins like sbt-site, ScalaDoc or mdoc.</p>
</div>
<div class="paragraph">
<p>A common example using ScalaDoc:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">// In build.sbt
Compile / doc / scalacOptions ++= Seq(
  "-groups",
  "-doc-title", "My Project Documentation"
)</code></pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">// Generate documentation with:
&gt; sbt doc  // Creates ScalaDoc in target/scala-2.13/api/</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_release_management">Release Management</h4>
<div class="paragraph">
<p>SBT can handle the entire release process, including version bumping, changelog generation, Git tagging, and publishing to various repositories or platforms.</p>
</div>
</div>
<div class="sect3">
<h4 id="_quality_analysis">Quality Analysis</h4>
<div class="paragraph">
<p>Integrate with code quality tools to analyze source code, check coverage, enforce styling rules, and generate quality reports as part of your development workflow.</p>
</div>
<div class="paragraph">
<p>For example, to check code coverage in your project, first add the scoverage plugin to your <code>project/plugins.sbt</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.9")</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then you can run coverage analysis:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">&gt; sbt coverage         // Enable code coverage tracking
&gt; sbt test            // Run your tests - this collects coverage data
&gt; sbt coverageReport  // Generate coverage report showing which code was tested</code></pre>
</div>
</div>
<div class="paragraph">
<p>The report will be generated in <code>target/scala-2.13/scoverage-report/</code> and includes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>HTML reports showing line-by-line coverage</p>
</li>
<li>
<p>Overall coverage statistics</p>
</li>
<li>
<p>Highlighted source code showing covered/uncovered lines</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>SBT is a powerful tool that transcends its role as a build tool, offering developers a versatile platform for managing, automating, and enhancing their development workflows. Whether you’re working on a small library or a large-scale application, SBT’s features and extensibility make it a valuable addition to the Scala ecosystem. SBT acts more as a development platform than a build tool and by understanding its capabilities and limitations, teams can leverage SBT to streamline their processes and focus on building great software.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Interop Summit. Why do we only import Java libraries?</title>
		<link>https://blog.lunatech.com//posts/2025-02-14-interop-summit</link>
		
		<dc:creator><![CDATA[Konstantin Kolmar]]></dc:creator>
        <pubDate>2025-02-14T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[jvm]]></category>
                }
             {
            <category><![CDATA[interop]]></category>
                }
             {
            <category><![CDATA[scala]]></category>
                }
             {
            <category><![CDATA[scala3]]></category>
                }
             {
            <category><![CDATA[kotlin]]></category>
                }
             {
            <category><![CDATA[gradle]]></category>
                }
             {
            <category><![CDATA[groovy]]></category>
                }
             {
            <category><![CDATA[we-know-scala]]></category>
                }
             {
            <category><![CDATA[scala-lujah]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-02-14-interop-summit</guid>

					<description>
                        <![CDATA[ The Java platform, including the Java language and Java Virtual Machine (JVM), was first released around 1995. At that time, Java was the only language running on the JVM. Soon, however, other languages followed, which addressed some of Java’s shortcomings while still leveraging its runtime and the vast collection of standard and third-party libraries and allowing integration with a large amount of existing Java code.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_short_history_of_the_java_platform">Short history of the Java platform</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Java platform, including the Java language and Java Virtual Machine (JVM), was first released around 1995. At that time, Java was the only language running on the JVM. Soon, however, other languages followed, which addressed some of Java’s shortcomings while still leveraging its runtime and the vast collection of standard and third-party libraries and allowing integration with a large amount of existing Java code.</p>
</div>
<div class="paragraph">
<p>Scala was one of the first such languages. Its development started in 2001, and the first release came out in 2004. Its main goal was to mix functional and object-oriented programming and to allow writing more concise code than Java.</p>
</div>
<div class="paragraph">
<p>Groovy was released in 2007 and introduced dynamic typing and improved scripting capabilities. Clojure also came out in 2007. As a Lisp dialect, its strengths lie in functional programming and metaprogramming.</p>
</div>
<div class="paragraph">
<p>Kotlin was one of the later major languages that entered the scene. Its implementation started in 2010, and the first stable release was in 2016. Kotlin was designed to be a nicer Java with seamless interoperability. Later, it became officially supported for Android development.</p>
</div>
<div class="paragraph">
<p>It is interesting to note that no new major languages have appeared in about 15 years now. This is probably because existing languages already cover the most important niches. Moreover, Java now includes quality-of-life features like lambdas, closures, lazy streams, records, and virtual threads, which had previously motivated the creation of new languages. Nowadays you would also need a large amount of tooling and libraries to support a new language, and probably some killer application or support and promotion from a large company.</p>
</div>
<div class="paragraph">
<p>Still, there is a large variety of less prominent languages on the JVM, including even some internal company languages. Many originally non-JVM languages have compilers that target JVM such as Jython for Python.</p>
</div>
<div class="paragraph">
<p>But given the large variety of available options, why do we only import libraries implemented in Java or in the language we are using? Well, it&#8217;s probably not a huge mystery. I bet you can name several important reasons yourself. But I think it&#8217;s still interesting to think about, so let&#8217;s review some of them.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_1_utility_libraries_are_implemented_in_each_language">1. Utility libraries are implemented in each language</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Small or utility libraries are simply implemented natively in each language to provide idiomatic APIs. Such implementations might be a part of the standard library or provided by third parties. A good example is JSON processing. There are a lot of third-party JSON libraries in Scala, often using typeclasses and other special Scala features. In contrast, in Kotlin JSON is supported by an official library in <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>. There is a similar situation with idiomatic libraries for dependency injection, web frameworks, and so on.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_2_few_large_unique_libraries">2. Few large unique libraries</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There is a lack of genuine need to import anything large from outside. What libraries unique to Kotlin, let alone other non-Java languages, would you want to use in your Scala code? Jetpack Compose is an example of a Kotlin library occupying a unique niche. It is the de facto default GUI framework on Android. However, since it&#8217;s a GUI framework you wouldn’t normally import it as a library, and you rarely see Scala code on Android anyway.</p>
</div>
<div class="paragraph">
<p>As for Scala, there are unique libraries that could be useful in Java or Kotlin code: Akka or Pekko, Spark, Gatling, or Flink. But they usually already provide bindings or APIs for Java, so you don&#8217;t need their Scala APIs. Many of them are even discontinuing their Scala API, or avoiding migration to Scala 3.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_3_focus_on_using_java_code">3. Focus on using Java code</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Java is one of the most popular languages ever created, so over its long history a lot of libraries for all kinds of purposes have been produced. This means that language authors of every JVM language make a special effort to provide an easy way to interact with Java dependencies.</p>
</div>
<div class="paragraph">
<p>The end result is that using Java code from Scala or Kotlin is fairly simple. You can call methods normally and give them arguments, extend classes and interfaces, and so on. Scala standard library supplies a <code>scala.jdk</code> package, that contains many facilities to assist with interoperability.</p>
</div>
<div class="paragraph">
<p>Of course, this is still not always completely straightforward. One obvious point of contention is nullability. When using Java libraries from Scala you usually need to wrap nearly everything in an <code>Option</code> to avoid null pointer exceptions. You may say that using Java libraries is not idiomatic, but even in the standard library, there are packages you may want to use occasionally: <code>java.nio.file</code>, <code>java.time</code>, Unicode support, and so on.</p>
</div>
<div class="paragraph">
<p>Here is an example of a Scala 3 extension to wrap the result of one Java method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">extension (p: Path)
  def parent: Option[Path] = Option(p.getParent)</code></pre>
</div>
</div>
<div class="paragraph">
<p>This approach is not ideal, because if you miss any wrappers, you&#8217;ll get a <code>NullPointerException</code> at runtime.</p>
</div>
<div class="paragraph">
<p>Scala 3 has added union types, so now you can declare nullable types directly: <code>MyType | Null</code>. It also has the <a href="https://docs.scala-lang.org/scala3/reference/experimental/explicit-nulls.html">explicit nulls</a> feature enabled by the <code>-Yexplicit-nulls</code> flag. This means that all values that can have a <code>null</code> value, including all values coming from Java, must have a nullable type. This reduces the <code>Option</code> boilerplate when dealing with Java code, but introduces a different kind of boilerplate: null-checking the results of functions that can never return null.</p>
</div>
<div class="paragraph">
<p>To improve this the recently released Scala 3.5 has introduced <a href="https://docs.scala-lang.org/scala3/reference/experimental/explicit-nulls.html#java-interoperability-and-flexible-types-1">flexible types</a> inspired by Kotlin&#8217;s <a href="https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types">platform types</a>. This feature is enabled by default but can be turned off with the <code>-Yno-flexible-types</code> flag. It means that values coming from Java can now be treated as either nullable or non-nullable. This offers the same safety guarantees as Java, so again it has reverted to the <code>Option</code> wrapper situation, and it&#8217;s possible to get null pointer exceptions again.</p>
</div>
<div class="paragraph">
<p>This development process demonstrates both how much effort forward interop receives and how hard it is to provide a good solution for some issues. Well, nulls wouldn&#8217;t have been a billion-dollar mistake otherwise.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_4_reverse_interoperability_is_complicated">4. Reverse interoperability is complicated</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Reverse interoperability refers to tools and techniques that allow developers to write code accessible from Java and potentially other JVM languages. However, it can be difficult to transparently incorporate features that are unique to a particular language. For instance, when calling Scala code from Java, implicit values must be explicitly constructed, which undermines the usability of the API.</p>
</div>
<div class="paragraph">
<p>Even in simpler cases reverse interoperability requires carefully marking your code with annotations or using some non-idiomatic constructs. For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">case class MountainRange(mountains: List[Mountain])
object MountainRange:
  @varargs
  @targetName("of3")
  @throws[IllegalArgumentException]
  def ^^^(mountains: Mountain*): MountainRange = {
    if (mountains.size != 3) throw IllegalArgumentException("Incorrect number of mountains")
    MountainRange(mountains.toList)
  }</code></pre>
</div>
</div>
<div class="paragraph">
<p>The annotations in this method cause the Scala compiler to produce a signature that can better interact with Java. <code>@varargs</code> means that the argument will be a Java <code>Array</code> instead of a Scala <code>Seq</code>, <code>targetName</code> gives it a stable alphanumeric name instead of a technical name mangled by the compiler, and <code>@throws</code> adds the corresponding "throws" declaration to the method signature.</p>
</div>
<div class="paragraph">
<p>Another interesting example that demonstrates how much of an afterthought reverse interop can be is trying to define an enumeration that extends <code>java.lang.Enum</code>. In Scala 3 this is straightforward:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">enum Mountain extends Enum[Mountain]:
  case Everest, Kilimanjaro, MontBlanc, Fujiyama</code></pre>
</div>
</div>
<div class="paragraph">
<p>Scala 3 compiler automatically generates calls to the <code>java.lang.Enum</code> constructor to initialize the values. But I don&#8217;t know a way to create a Java-compatible enumeration from Scala 2. Maybe it&#8217;s not possible at all!</p>
</div>
<div class="paragraph">
<p>Other features reverse interoperability has to handle may include:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Static methods and constant values.</p>
</li>
<li>
<p>Class fields, getters, and setters, because many JVM languages try to improve their handling in some way.</p>
</li>
<li>
<p>Optional method arguments and default values. Java doesn&#8217;t allow those, but most other JVM languages do.</p>
</li>
<li>
<p>Different visibility modes, such as Scala&#8217;s <code>sealed</code> or Kotlin&#8217;s <code>internal</code>.</p>
</li>
<li>
<p>Concurrency primitives. Every language has something unique and barely compatible with each other. For example, Scala uses Futures or various IO libraries, Kotlin has coroutines in its standard library, and Java has recently added virtual threads.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Imagine having to support this menagerie for multiple languages, each with its own assumptions and idioms, changing and updating over time. If every language provided bindings or APIs for every other language, the complexity would explode.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_5_concerns_about_runtime_dependencies">5. Concerns about runtime dependencies</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Using libraries from another language usually implies including that language&#8217;s standard library as a runtime dependency. This slows down the build and increases distribution sizes. The effect may not be large in absolute terms, but still provides enough incentive for library authors to design their libraries to avoid unnecessary dependencies on the entire standard library of a whole language.</p>
</div>
<div class="paragraph">
<p>As a consequence of those reasons Java naturally serves as the common denominator to mediate between JVM languages.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_case_study">Case study</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Situations where you need to interact between non-Java languages do happen but are fairly unusual. One interesting example from our team involved configuring access to intranet repositories (without internet access) in our Gradle builds.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s adopt the following assumptions:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>We are using Kotlin for our Gradle builds, because Kotlin is statically typed and its tooling and IDE support are better than Groovy’s.</p>
</li>
<li>
<p>Multiple teams publish their artifacts into their own repositories on the shared Artifactory. Different projects need different dependencies, so our goal is to give the project maintainers a simple way to add the repositories with the artifacts they need. We want to have an extension method on the <code>RepositoryHandler</code>, similar to the idiomatic Gradle methods such as <code>mavenCentral()</code> or <code>gradlePluginPortal()</code>:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-kotlin" data-lang="kotlin">repositories { // this: RepositoryHandler =&gt;
    mavenInternal("maven-releases")
    mavenInternal("gradle-plugins")
    mavenInternal("other-team-artifacts")
}</code></pre>
</div>
</div>
</li>
<li>
<p>We have a local plugin to set the repository URL and configure a way to obtain a login token from the environment:</p>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-groovy" data-lang="groovy">def extendRepositories(RepositoryHandler repositories) {
    if (repositories !instanceof ExtensionAware) return

    repositories.ext {
        mavenInternal = { repoName -&gt;
            repositories.maven {
                name = repoName
                url = "https://artifactory.example.com/$repoName"
                credentials {
                    token = providers.environmentVariable("ARTIFACTORY_TOKEN")
                            .orElse(providers.systemProperty("gradle.wrapperPassword"))
                            .orNull
                }
            }
        }
    }
}</code></pre>
</div>
</div>
</li>
</ol>
</div>
<div class="paragraph">
<p>The problem here is that Gradle can automatically execute Groovy builds, but for Kotlin builds it needs to download a special plugin, and to download the plugin without internet access, it requires the internal repository to be already configured, creating a Catch-22 type of problem. This means the repository configuration plugin above has to be implemented in Groovy.</p>
</div>
<div class="paragraph">
<p>In the Groovy build flavor, you can directly use methods defined in an <a href="https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html">extra properties extension</a>. But Kotlin doesn&#8217;t understand that approach. It can&#8217;t interact with standard Groovy extension methods either. Groovy implements them by modifying Groovy metaclasses, but in Kotlin extension methods are just syntax sugar, and at runtime are implemented as normal methods taking the receiver as the first argument.</p>
</div>
<div class="paragraph">
<p>In the end, the solution was to create an intermediate plugin in Kotlin, that provides a Kotlin-style extension method. It extracts Groovy <code>Closure</code> from the extra properties extension, casts it to the appropriate type, and calls it using Groovy API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-kotlin" data-lang="kotlin">fun RepositoryHandler.mavenInternal(path: String) {
    ((this as ExtensionAware).extra["mavenInternal"] as Closure&lt;*&gt;).call(path)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is still not ideal, because this helper method can&#8217;t be shared between the intermediate plugin build and implementation, so it has to be copy-pasted into several places. Nevertheless, this achieves the goal of having nice repository declarations in the user-level Kotlin build.</p>
</div>
<div class="paragraph">
<p>This is an example of how convoluted interoperability can look when assumptions and idioms from different languages and libraries come in conflict with each other.</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>Recap of the Joy of Coding Meetup at Lunatech</title>
		<link>https://blog.lunatech.com//posts/2025-02-13-joy-of-coding-at-lunatech</link>
		
		<dc:creator><![CDATA[]]></dc:creator>
        <pubDate>2025-02-13T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[documentation]]></category>
                }
             {
            <category><![CDATA[automation]]></category>
                }
             {
            <category><![CDATA[opentelemetry]]></category>
                }
             {
            <category><![CDATA[monitoring]]></category>
                }
             {
            <category><![CDATA[grafana]]></category>
                }
             {
            <category><![CDATA[performance]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-02-13-joy-of-coding-at-lunatech</guid>

					<description>
                        <![CDATA[ On February 12th, Lunatech had the privilege of hosting the Joy of Coding meetup at our office in Rotterdam.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>On February 12th, Lunatech had the privilege of hosting the Joy of Coding meetup at our office in Rotterdam.</p>
</div>
<div class="paragraph">
<p>We were excited to bring developers from across the city together to reconnect and share knowledge in an open and welcoming environment.</p>
</div>
<div class="paragraph">
<p>The evening began with a warm welcome, giving attendees the opportunity to mingle over delicious pizza. With the room buzzing with conversation, it was clear that everyone was eager to dive into the evening’s insightful sessions.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-13-joy-of-coding-at-lunatech/networking.png" alt="Introduction over pizza" width="600">
</div>
<div class="title">Figure 1. Introduction over pizza</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_coding_your_documentation">Coding Your Documentation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The first session of the evening, "Coding Your Documentation" by Hubert Klein Ikkink, explored how developers can take a structured and automated approach to documentation.</p>
</div>
<div class="paragraph">
<p>Writing documentation is often seen as a tedious task, but Hubert demonstrated how code-driven techniques can make the process more efficient, maintainable, and even enjoyable.</p>
</div>
<div class="paragraph">
<p>Through practical examples, the session covered strategies such as using markup languages, automation tools, and integrating documentation directly into the development workflow. Hubert showcased how well-documented projects not only improve collaboration within teams but also enhance the onboarding process for new developers and contribute to overall software quality.</p>
</div>
<div class="paragraph">
<p>Attendees walked away with actionable insights on how to streamline documentation efforts, ensuring that code remains well-documented without slowing down development. The talk was a great reminder that good documentation is just as important as the code itself.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-13-joy-of-coding-at-lunatech/documentation.png" alt="Coding Your Documentation" width="600">
</div>
<div class="title">Figure 2. Coding Your Documentation</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reaching_operational_excellence_using_opentelemetry">Reaching Operational Excellence Using OpenTelemetry</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Riccardo Lippolis took the stage to talk about OpenTelemetry and its critical role in ensuring operational excellence. His session, "Reaching Operational Excellence Using OpenTelemetry," focused on how developers can easily implement standardized APIs for logging and metrics across distributed services.</p>
</div>
<div class="paragraph">
<p>Through practical demonstrations, attendees learned how OpenTelemetry allows for seamless service monitoring, making it easier to identify and solve issues in a production environment. This session provided valuable insights that our community can apply directly to their own work.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-13-joy-of-coding-at-lunatech/telemetry.png" alt="Reaching Operational Excellence Using OpenTelemetry" width="600">
</div>
<div class="title">Figure 3. Reaching Operational Excellence Using OpenTelemetry</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_networking_and_drinks">Networking and Drinks</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As the talks concluded, the evening wrapped up with drinks and a networking session, giving everyone the opportunity to continue their conversations, exchange ideas, and make new connections.</p>
</div>
<div class="paragraph">
<p>The atmosphere was energizing, and it was clear that the local developer community is eager to keep pushing the boundaries of tech.</p>
</div>
<div class="paragraph">
<p>See you at the next meetup!</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>ZGC vs G1GC for Scala</title>
		<link>https://blog.lunatech.com//posts/2025-02-07-zgc-vs-g1gc-for-scala</link>
		
		<dc:creator><![CDATA[Utku Aydın]]></dc:creator>
        <pubDate>2025-02-07T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[zgc]]></category>
                }
             {
            <category><![CDATA[gen-zgc]]></category>
                }
             {
            <category><![CDATA[g1]]></category>
                }
             {
            <category><![CDATA[g1gc]]></category>
                }
             {
            <category><![CDATA[scala]]></category>
                }
             {
            <category><![CDATA[jvm]]></category>
                }
             {
            <category><![CDATA[we-know-scala]]></category>
                }
             {
            <category><![CDATA[scala-lujah]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2025-02-07-zgc-vs-g1gc-for-scala</guid>

					<description>
                        <![CDATA[ When it comes to high-performance Scala applications, memory management plays a crucial role in maintaining efficiency and stability. The JVM's Garbage Collection (GC) mechanisms help developers avoid memory leaks and memory management while balancing latency and throughput. Two prominent GC strategies—Garbage First (G1GC) and Z Garbage Collector (ZGC)—offer different benefits depending on application needs. In this post, we'll explore these two GC approaches, their configurations, benchmarks, and best-use scenarios for Scala applications.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When it comes to high-performance Scala applications, memory management plays a crucial role in maintaining efficiency and stability. The JVM&#8217;s Garbage Collection (GC) mechanisms help developers avoid memory leaks and memory management while balancing latency and throughput. Two prominent GC strategies—Garbage First (G1GC) and Z Garbage Collector (ZGC)—offer different benefits depending on application needs. In this post, we&#8217;ll explore these two GC approaches, their configurations, benchmarks, and best-use scenarios for Scala applications.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_garbage_first_gc_g1gc">Garbage First GC (G1GC)</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_what_is_g1gc">What is G1GC?</h3>
<div class="paragraph">
<p>G1GC was introduced in JDK 7 and became the default GC in JDK 9. It&#8217;s designed to optimize both latency and throughput by dividing the heap into regions and prioritizing the collection of those with the most garbage. Unlike traditional GC methods, G1GC performs concurrent marking to reduce stop-the-world pauses, enhancing application performance.</p>
</div>
</div>
<div class="sect2">
<h3 id="_when_to_use_g1gc">When to Use G1GC</h3>
<div class="ulist">
<ul>
<li>
<p>G1GC should be used in applications that require predictable pause times.</p>
</li>
<li>
<p>It is suitable for systems where throughput is more critical than achieving ultra-low latency.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_when_not_to_use_g1gc">When Not to Use G1GC</h3>
<div class="ulist">
<ul>
<li>
<p>G1GC is not ideal for applications with very large heaps that exceed a few hundred gigabytes.</p>
</li>
<li>
<p>It should be avoided in workloads with extreme garbage generation, as pause times may increase in edge cases.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_z_garbage_collector_zgc">Z Garbage Collector (ZGC)</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_what_is_zgc">What is ZGC?</h3>
<div class="paragraph">
<p>ZGC, introduced in JDK 11, is a low-latency garbage collector designed to maintain sub-millisecond pause times regardless of heap size. It performs most of its work concurrently, including marking and compaction, ensuring minimal disruption to application performance. It ZGC can handle heap sizes up to 16 terabytes, making it an excellent choice for large-scale applications.</p>
</div>
</div>
<div class="sect2">
<h3 id="_when_to_use_zgc">When to Use ZGC</h3>
<div class="ulist">
<ul>
<li>
<p>ZGC is recommended for real-time systems that have strict latency requirements.</p>
</li>
<li>
<p>It is well-suited for applications that require efficient scalability with very large heaps.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_when_not_to_use_zgc">When Not to Use ZGC</h3>
<div class="ulist">
<ul>
<li>
<p>ZGC should not be used in applications that are constrained by CPU resources.</p>
</li>
<li>
<p>It is not ideal for workloads where high throughput is more critical than maintaining low latency.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_generational_zgc_the_cherry_on_top">Generational ZGC: The Cherry on Top</h3>
<div class="paragraph">
<p>Generational ZGC introduces separate young and old generations, optimizing memory reclamation by focusing on short-lived objects more frequently. This approach reduces the overhead associated with managing short-lived objects, which are common in most workloads. Additionally, it further minimizes CPU and memory bandwidth usage compared to the non-generational ZGC. Despite these optimizations, Generational ZGC retains its ultra-low pause times, remaining in the sub-millisecond range. It continues to efficiently handle large heaps, with multi-terabyte support still intact. Like its predecessor, Generational ZGC performs marking, relocation, and compaction concurrently, making sure there are no disruptions in application performance.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_configuring_scala_applications_for_gc">Configuring Scala Applications for GC</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To configure GC in Scala applications, appropriate Java options should be set in build.sbt.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-scala" data-lang="scala">javaOpts += "-XX:+UseZGC -XX:+ZGenerational"</code></pre>
</div>
</div>
<div class="paragraph">
<p>In container environments, the configuration can be achieved by including the required flags in the java options environment variable (may vary between JDK distributions).</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-console" data-lang="console">JAVA_OPTS = "-XX:+UseZGC -XX:+ZGenerational …"</code></pre>
</div>
</div>
<div class="paragraph">
<p>Both garbage collectors also have additional flags that can be included to further fine tune their behavior depending on the use case. These are available in their respective documentation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_benchmarking_g1gc_vs_zgc">Benchmarking G1GC vs ZGC</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_setup">Setup</h3>
<div class="ulist">
<ul>
<li>
<p>The benchmarking tests were conducted in a Kubernetes cluster with 2 CPUs and 4GB of memory allocated.</p>
</li>
<li>
<p>Java options were pre-configured specifically for G1GC and Generational ZGC to ensure accurate comparisons.</p>
</li>
<li>
<p>The test workload consisted of a streaming application that processed messages at varying rates of 300, 600, and 900 messages per second.</p>
</li>
<li>
<p>Each test run included a warm-up phase lasting 10 minutes to allow the system to reach a stable state.</p>
</li>
<li>
<p>Following the warm-up, data recording was conducted for 20 minutes to capture performance metrics.</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_observations">Observations</h3>
<div class="sect3">
<h4 id="_300_messages_per_second_g1">300 messages per second G1</h4>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-07-zgc-vs-g1gc-for-scala/300-g1.png" alt="300 G1" width="600">
</div>
</div>
</div>
<div class="sect3">
<h4 id="_300_messages_per_second_zgc">300 messages per second ZGC</h4>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-07-zgc-vs-g1gc-for-scala/300-zgc.png" alt="300 ZGC" width="600">
</div>
</div>
</div>
<div class="sect3">
<h4 id="_600_messages_per_second_g1">600 messages per second G1</h4>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-07-zgc-vs-g1gc-for-scala/600-g1.png" alt="600 G1" width="600">
</div>
</div>
</div>
<div class="sect3">
<h4 id="_600_messages_per_second_zgc">600 messages per second ZGC</h4>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-07-zgc-vs-g1gc-for-scala/600-zgc.png" alt="600 ZGC" width="600">
</div>
</div>
</div>
<div class="sect3">
<h4 id="_900_messages_per_second_g1">900 messages per second G1</h4>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-07-zgc-vs-g1gc-for-scala/900-g1.png" alt="900 G1" width="600">
</div>
</div>
</div>
<div class="sect3">
<h4 id="_900_messages_per_second_zgc">900 messages per second ZGC</h4>
<div class="imageblock">
<div class="content">
<img src="../media/2025-02-07-zgc-vs-g1gc-for-scala/900-zgc.png" alt="900 ZGC" width="600">
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>ZGC maintained ultra-low latency across all sample sizes.</p>
</li>
<li>
<p>G1GC delivered predictable pause times but showed increased latency under heavy load.</p>
</li>
<li>
<p>Generational ZGC improved short-lived object management, enhancing overall efficiency.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>ZGC and G1GC both offer unique advantages for Scala applications:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>ZGC is the best choice for ultra-low latency and massive heap scalability.</p>
</li>
<li>
<p>G1GC is ideal for general-purpose applications requiring predictable performance tuning.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Ultimately, selecting the right GC strategy depends on workload characteristics and performance requirements. Benchmarking under real-world conditions remains the key to making an informed decision.</p>
</div>
<div class="paragraph">
<p>SCALA-LUJAH! Happy coding!</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>JVM vs JVM</title>
		<link>https://blog.lunatech.com//posts/2024-11-29-jvm-vs-jvm</link>
		
		<dc:creator><![CDATA[Nika Shamova]]></dc:creator>
        <pubDate>2024-11-29T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[java]]></category>
                }
             {
            <category><![CDATA[jvm]]></category>
                }
             {
            <category><![CDATA[java-vs-world]]></category>
                }
             {
            <category><![CDATA[java-over-java]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2024-11-29-jvm-vs-jvm</guid>

					<description>
                        <![CDATA[ You’ve probably heard people talk about different JVMs, each claiming to be the best. It made me wonder: why are there so many? What makes one JVM better than another? In this article, we’ll try to break down what the JVM is, how it works, and why there are so many different implementations.]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You’ve probably heard people talk about different JVMs, each claiming to be the best. It made me wonder: why are there so many? What makes one JVM better than another? In this article, we’ll try to break down what the JVM is, how it works, and why there are so many different implementations.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_basic_concepts">Basic Concepts</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_java_abbreviation_overload_jdk_jre_jvm">Java Abbreviation Overload: JDK, JRE, JVM</h3>
<div class="paragraph">
<p>If you’re working with Java, you’ve likely encountered terms like JVM, JRE, and JDK. But what do they mean, and how are they connected? Let’s break it down:</p>
</div>
<div class="sect3">
<h4 id="_jdk_java_development_kit">JDK (Java Development Kit)</h4>
<div class="paragraph">
<p>This is a toolkit designed for Java developers. It includes everything you need to write and build Java applications:
- A compiler (<code>javac</code>) to turn Java source code into bytecode.
- Development libraries such as tools for debugging, monitoring, and packaging Java programs.
- The JRE (our next guest, see below).</p>
</div>
</div>
<div class="sect3">
<h4 id="_jre_java_runtime_environment">JRE (Java Runtime Environment)</h4>
<div class="paragraph">
<p>This is the software environment required to run Java applications:
- Runtime libraries: Core Java libraries (e.g., <code>java.lang</code>, <code>java.util</code>) and APIs for features like file I/O, networking, and concurrency.
- The JVM (another guest, which is described below), which executes the bytecode.</p>
</div>
</div>
<div class="sect3">
<h4 id="_jvm_java_virtual_machine">JVM (Java Virtual Machine)</h4>
<div class="paragraph">
<p>At the core of the Java runtime, it is responsible for:
- Loading and executing Java bytecode, a platform-independent instruction set generated when Java code is compiled.
- Optimizing performance with features like JIT (Just-In-Time) Compilation, which translates bytecode into machine-specific code during execution.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_java_bytecode">Java bytecode</h3>
<div class="paragraph">
<p>Bytecode is an intermediate, low-level language into which Java source code is compiled. It allows Java applications to run on any platform with a JVM, enabling the "write once, run anywhere" promise.</p>
</div>
</div>
<div class="sect2">
<h3 id="_jit_just_in_time_compilation">JIT (Just-In-Time) Compilation</h3>
<div class="paragraph">
<p>To improve speed, the JVM uses JIT to dynamically translate bytecode into native machine code at runtime. This reduces interpretation overhead, making applications faster.</p>
</div>
</div>
<div class="sect2">
<h3 id="_aot_ahead_of_time_compilation">AOT (Ahead-Of-Time) Compilation</h3>
<div class="paragraph">
<p>While JIT improves performance during execution, some environments benefit from Ahead-Of-Time (AOT) Compilation, which compiles bytecode into native code before runtime. This approach is often used in resource-constrained environments, where startup speed and memory efficiency are critical.</p>
</div>
</div>
<div class="sect2">
<h3 id="_how_do_they_fit_together">How Do They Fit Together?</h3>
<div class="ulist">
<ul>
<li>
<p>JDK: Developers use it to create Java applications.</p>
</li>
<li>
<p>JRE: Users rely on it to run Java applications.</p>
</li>
<li>
<p>JVM: This is the part of the JRE that runs Java bytecode.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2024-11-29-jvm-vs-jvm/jdk-jre-jvm.png" alt="JDK &lt; JRE &lt; JVM" width="200">
</div>
</div>
<div class="paragraph">
<p>During execution, the JVM can:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Use the JIT compiler to boost performance by translating bytecode to machine code on the fly.</p>
</li>
<li>
<p>Optionally benefit from AOT compilation to further improve startup times and efficiency in specific scenarios.</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="_tldr">TLDR</h4>
<div class="paragraph">
<p>The JDK includes the JRE, and the JRE contains the JVM. Together, they enable Java programs to be developed, executed, and optimized for a wide variety of platforms and use cases.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_write_once_run_anywhere">Write Once, Run Anywhere</h3>
<div class="paragraph">
<p>The JVM is an abstract computing machine that enables Java applications to run on any hardware or operating system. It translates platform-independent bytecode into machine-specific instructions, ensuring seamless compatibility across environments.</p>
</div>
<div class="paragraph">
<p>In simpler terms, JVM developers handle the heavy lifting. Their job is to build a robust, cross-platform JVM that works on all environments. This allows Java developers to focus on writing code without worrying too much about the specifics of different platforms. (Though, let’s be real—sometimes they still have to consider it, but that’s a story for another day.)</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_jvm_history">JVM History</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_the_beginning_of_jvm">The Beginning of JVM</h3>
<div class="sect3">
<h4 id="_first_implementation_of_the_jvm">First Implementation of the JVM</h4>
<div class="paragraph">
<p>The first implementation of the JVM was part of JDK 1.0, released in January 1996. Sun Microsystems developed this initial JVM in C. It was bundled with the early versions of the Java Development Kit (JDK), which included tools such as <code>javac</code> (the Java compiler) and runtime libraries.</p>
</div>
</div>
<div class="sect3">
<h4 id="_other_early_implementations">Other Early Implementations</h4>
<div class="paragraph">
<p>After the initial Sun JVM, several other JVM implementations were developed:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Kaffe</strong>: An independent, open-source implementation of the JVM. It aimed to provide a lightweight alternative to Sun&#8217;s JVM, which is well-suited for embedded systems.</p>
</li>
<li>
<p><strong>IBM J9 (later OpenJ9)</strong>: IBM&#8217;s implementation focused on enterprise environments, emphasizing performance and tuning capabilities.</p>
</li>
<li>
<p><strong>Oracle JRockit</strong>: A JVM optimized for server-side performance, especially in low-latency environments. Oracle acquired it and later merged features with the HotSpot JVM.</p>
</li>
<li>
<p><strong>HotSpot JVM</strong>: Originally developed by Longview Technologies, HotSpot was acquired by Sun Microsystems. It introduced Just-In-Time (JIT) compilation and adaptive optimization techniques. HotSpot eventually became the default JVM in the Java SE platform.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_is_the_deal_with_openjdk_and_oracle_jdk">What is the Deal with OpenJDK and Oracle JDK?</h3>
<div class="paragraph">
<p>OpenJDK and Oracle JDK are closely related, especially since Java 11. OpenJDK is the open-source implementation of the Java SE Platform, while Oracle JDK is a commercial build based on OpenJDK. Both share the same codebase, meaning their functionality is nearly identical from Java 11 onward.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Oracle JDK historically</strong>: included exclusive "commercial features" like Flight Recorder, Java Mission Control, and Application Class-Data Sharing. However, these features were added to OpenJDK starting with Java 11, eliminating most differences between the two.</p>
</li>
<li>
<p>The main distinction now lies in licensing and support. OpenJDK is free under the GNU General Public License (GPL), while Oracle JDK requires a commercial license for production use and comes with additional long-term support options for businesses. Essentially, OpenJDK is the foundation for Oracle JDK, and they are almost identical in technical terms for modern Java versions.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_jvm_vs_jvm">JVM vs JVM</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_so_many_jvms_what_is_the_difference">So Many JVMs, What is the Difference?</h3>
<div class="paragraph">
<p>There are so many JDKs and JVMs available these days. Let’s explore a few of them to see how they differ and what unique features they offer!</p>
</div>
<div class="sect3">
<h4 id="_openjdk">OpenJDK</h4>
<div class="paragraph">
<p>The Open Java Development Kit (OpenJDK) is an open-source implementation of the Java Platform, Standard Edition (Java SE).</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Reference Implementation</strong>: OpenJDK is the official reference implementation of Java SE, ensuring compliance with the Java SE specifications. Many other distributions use it as a core.</p>
</li>
<li>
<p><strong>Regular Release Cycle</strong>: OpenJDK follows a six-month release cycle, with Long-Term Support (LTS) versions every three years.</p>
</li>
<li>
<p><strong>Community-Driven</strong>: Features like improved garbage collectors, API updates, and performance optimizations are developed as an open-source.</p>
</li>
<li>
<p><strong>Cross-Platform</strong>: OpenJDK supports major operating systems like Linux, macOS, and Windows, as well as architectures like x86, ARM, and RISC-V.</p>
</li>
<li>
<p><strong>Licensing</strong>: OpenJDK is distributed under a GPL license, allowing it to be used freely for all purposes, including commercial applications.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_oracle_jdk">Oracle JDK</h4>
<div class="paragraph">
<p>The Oracle JDK is Oracle’s distribution of the Java Development Kit. It shares the same codebase as the open-source OpenJDK but comes with some proprietary features and licensing.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Oracle JDK is based on OpenJDK but includes additional optimizations and patches.</p>
</li>
<li>
<p>Oracle ensures backward compatibility and long-term support for enterprise users.</p>
</li>
<li>
<p>Access to critical bug fixes before they are included in publicly available releases.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_graalvm">GraalVM</h4>
<div class="paragraph">
<p>GraalVM is a powerful version of the JDK that offers AOT native image compilation. It also enables  integration between multiple programming languages using the Truffle framework. With Truffle, programs written in different supported languages can work together easily. For instance, a JavaScript program can call Ruby methods and share data without duplicating it.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Compiler: GraalVM introduces the Graal JIT Compiler, a replacement for the traditional HotSpot C2 compiler.</p>
<div class="ulist">
<ul>
<li>
<p>Written in Java, the compiler is highly modular and easier to maintain and extend than older compilers written in C++.</p>
</li>
<li>
<p>Implements advanced optimizations like speculative optimizations, partial escape analysis, and inlining across multiple languages.</p>
</li>
</ul>
</div>
</li>
<li>
<p>Polyglot Support: GraalVM uses the Truffle language implementation framework, a platform for building interpreters for various languages. Each language runtime is implemented as a Truffle interpreter. Truffle is a framework for building language interpreters. When combined with the Graal compiler, these interpreters are automatically optimized with just-in-time (JIT) compilation, enabling programs running on them to achieve performance comparable to standard Java.</p>
</li>
<li>
<p>Native Image: Provides an AOT compilation feature called native image. Transforms JVM-based applications into standalone executables with reduced startup times and memory footprints.</p>
</li>
<li>
<p>Implementation Base: GraalVM builds on top of the OpenJDK HotSpot JVM. It replaces components like the compiler while retaining others, such as the garbage collector, class loader, and bytecode interpreter.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_azul_jdk">Azul JDK</h4>
<div class="paragraph">
<p>Azul Systems provides two JDK distributions: Zulu and Zing.</p>
</div>
<div class="paragraph">
<p><strong>Zulu</strong>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A fully open-source JDK based on OpenJDK, claimed to be the world’s most secure and stable build of OpenJDK.</p>
</li>
<li>
<p>Delivers stabilized security builds.</p>
</li>
<li>
<p>Legacy Production Support for Java versions that are end of life by OpenJDK and Oracle including Java 6 &amp; 7 (but it has to be paid).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><strong>Zing (Azul Platform Prime)</strong>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A commercial JDK designed for extreme performance and low-latency requirements.</p>
</li>
<li>
<p>The Falcon JIT compiler enhances performance through advanced speculative optimizations. Built on LLVM, it executes Java code 20–50% faster.</p>
</li>
<li>
<p>ReadyNow! Technology: It allows the JVM to be restored from a snapshot of another JVM, enabling faster startup times and optimized performance.</p>
</li>
<li>
<p>The C4 Garbage Collector: A pauseless, generational GC. It eliminates most stop-the-world pauses, allowing applications to run smoothly during garbage collection.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_use_cases">Use-Cases</h3>
<div class="paragraph">
<p>Choosing a JVM doesn’t have to be a grand philosophical debate—it really depends on what you need and how much effort or money you’re willing to invest. Let’s break it down.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>If you’re just building something straightforward with a handful of users and don’t see the point of adding unnecessary complexity, go with <strong>OpenJDK</strong>. It’s free, dependable, and perfectly capable of handling your needs. Let’s face it, your 100 users won’t notice the difference, so why overthink it?</p>
</li>
<li>
<p>For the big, established enterprises out there, where your codebase is a mix of old systems (possibly older than some of your interns) and shiny new features, <strong>Oracle JDK</strong> might be worth considering. Sure, it comes with a price tag, but you’ll have dedicated support and the peace of mind that your massive, mission-critical applications are in good hands.</p>
</li>
<li>
<p>If you’re a fan of Java but like to keep your options open, dabbling in other languages or running cutting-edge setups with serverless architectures and microservices, <strong>GraalVM</strong> could be your match. The free Community Edition is great if you’re on a budget, but the Enterprise Edition offers powerful features if you’re ready to splurge a little for performance.</p>
</li>
<li>
<p>Not an Oracle fan? Don’t need fancy bells and whistles? Enter <strong>Zulu</strong>, the practical, no-nonsense choice for developers who just want a solid, affordable JVM alternative. It’s reliable, efficient, and does the job without any drama—perfect for those who like to keep things simple.</p>
</li>
<li>
<p>And for those working with massive, memory-hungry applications that demand peak performance, <strong>Zing</strong> is the way to go. It’s designed for situations where every ounce of garbage collection optimization matters. Yes, it’s a premium option, but when your application has to run fast and smooth, the investment can make all the difference.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>And here you can see the algorithm, but don&#8217;t take it too seriously!</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../media/2024-11-29-jvm-vs-jvm/jvm-vs-jvm.png" alt="How to choose the right JVM" width="400">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_final_thoughts">Final Thoughts</h3>
<div class="paragraph">
<p>The JVM you choose should align with your project’s size, complexity, and budget. For small projects, OpenJDK or Zulu are often more than enough. For larger enterprises or performance-focused teams, investing in solutions like Oracle JDK, GraalVM, or Zing can pay off. Explore your options, and pick what works best for your needs!</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The JVM has evolved significantly since its debut with JDK 1.0, expanding from a single implementation to a diverse ecosystem of high-performance, specialized VMs. Building your own JVM or JDK requires deep knowledge of the Java specifications, low-level programming expertise, and a commitment to testing and optimization. If you&#8217;re genuinely considering this challenge, I must admit, I&#8217;m impressed! Best of luck! It&#8217;s a journey that will require immense dedication and effort!</p>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
         
	<item>
		<title>AspectJ vs Spring AOP vs Quarkus: Aop Showdown</title>
		<link>https://blog.lunatech.com//posts/2024-11-22-aop-showdown</link>
		
		<dc:creator><![CDATA[Natan Tesfaye]]></dc:creator>
        <pubDate>2024-11-15T00:00:00.000Z</pubDate>
         
             {
            <category><![CDATA[java]]></category>
                }
             {
            <category><![CDATA[aop]]></category>
                }
             {
            <category><![CDATA[aspectj]]></category>
                }
             {
            <category><![CDATA[spring-aop]]></category>
                }
             {
            <category><![CDATA[java-vs-world]]></category>
                }
             {
            <category><![CDATA[java-over-java]]></category>
                }
             {
            <category><![CDATA[en]]></category>
                }
             
        
		<guid isPermaLink="false">https://blog.lunatech.com//posts/2024-11-22-aop-showdown</guid>

					<description>
                        <![CDATA[ Imaging you're developing a simple program, and you want to log every time a method is called. One option to do that is calling]]></description>
                    <content:encoded><![CDATA[
                    <div class="sect2">
<h3 id="_overview">Overview</h3>
<div class="paragraph">
<p>Imaging you&#8217;re developing a simple program, and you want to log every time a method is called. One option to do that is calling
the logger in every method.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">// Without AOP
public class UserService {
    public void createUser(String name) {
        System.out.println("Logging: createUser method called with name: " + name); // Logging logic
        System.out.println("User created: " + name);
    }
}

public class ProductService {
    public void addProduct(String product) {
        System.out.println("Logging: addProduct method called with product: " + product); // Logging logic
        System.out.println("Product added: " + product);
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>But that is inefficient, and repetitive. Instead, We can use logging aspect  to handle all the logging when methods
are called.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LoggingAspect {

    // Pointcut: Matches all methods in UserService and ProductService classes
    @Pointcut("execution(* *Service.*(..))")
    public void userServiceMethods() {}

    // Logging logic before the method execution
    @Before("userServiceMethods()")
    public void logUserService() {
        System.out.println("Logging: createUser method called.");
    }

    @Before("productServiceMethods()")
    public void logProductService() {
        System.out.println("Logging: addProduct method called.");
    }
}

public class UserService {
    public void createUser(String name) {
        System.out.println("User created: " + name); // Core business logic
    }
}

public class ProductService {
    public void addProduct(String product) {
        System.out.println("Product added: " + product); // Core business logic
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When developing an application, you often encounter situations where certain functionality needs to be applied across various parts of the system—such as logging, error handling, or security. These are known as <strong>cross-cutting concerns</strong>, and traditionally, you&#8217;d end up repeating code across multiple classes or methods, leading to poor maintainability and scattered logic. This is where <strong>Aspect-Oriented Programming (AOP)</strong> comes in, allowing you to modularize these concerns separately from your business logic, making your code cleaner and easier to manage.</p>
</div>
<div class="paragraph">
<p>So, the purpose of Aspect-Oriented Programming (AOP) is to reduce code scattering and code tangling, improving the overall organization and maintainability of your code.</p>
</div>
<div class="paragraph">
<p><strong>Code Scattering</strong>: This occurs when the same functionality (like logging or security) is implemented repeatedly in multiple places across the codebase. AOP reduces scattering by centralizing such functionalities into modular components (aspects), so they only need to be defined once and can be applied wherever necessary.</p>
</div>
<div class="paragraph">
<p><strong>Code Tangling</strong>: This happens when multiple concerns (e.g., business logic, logging, error handling) are intertwined within the same code, making it difficult to understand or modify. AOP resolves this by separating concerns into distinct modules, allowing the business logic to remain clean and focused.
By addressing these issues, AOP enhances code modularity, making the codebase easier to manage, extend, and test.</p>
</div>
<div class="paragraph">
<p><strong>Key Concepts in AOP</strong></p>
</div>
<div class="paragraph">
<p><strong>Join Point</strong>: A point during the execution of a script.</p>
</div>
<div class="paragraph">
<p><strong>Pointcut</strong>: A regular expression that matches join points.</p>
</div>
<div class="paragraph">
<p><strong>Advice</strong>: Action Taken by an aspect at a join point.</p>
</div>
<div class="paragraph">
<p><strong>Aspect</strong>: A modularization of concerns that cuts across multiple objects.</p>
</div>
<div class="paragraph">
<p><strong>Weaving</strong>: process of integrating aspects (modularized cross-cutting concerns) into the main application code
at Join Points.</p>
</div>
</div>
<div class="sect2">
<h3 id="_aspectj">AspectJ</h3>
<div class="paragraph">
<p>AspectJ is an aspect-oriented extension to Java and one of the most robust implementations of AOP. It allows developers to modularize cross-cutting concerns and works seamlessly with any Java class. AspectJ supports compile-time, post-compile-time, and load-time weaving.</p>
</div>
<div class="paragraph">
<p>Example: Logging with AspectJ</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LoggingAspect {

    // Pointcut: Matches methods in classes under the package 'service'
    @Pointcut("execution(* service..*(..))")
    public void serviceMethods() {}

    // Logging logic applied before method execution
    @Before("serviceMethods()")
    public void logMethodExecution() {
        System.out.println("Logging: A service method was called.");
    }
}

public class UserService {
    public void createUser(String name) {
        System.out.println("User created: " + name); // Core business logic
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>AspectJ offers flexibility with annotations or an XML-based configuration for managing aspects, making it highly versatile in various Java projects. AspectJ is framework-independent. It works directly with raw Java classes, making it suitable for standalone applications or projects not tied to any ecosystem.</p>
</div>
<div class="paragraph">
<p>AspectJ provides an extensive and fine-grained join point model, allowing developers to intercept and manipulate almost any point in a program&#8217;s execution. This includes Method executions, Constructor calls, etc.</p>
</div>
</div>
<div class="sect2">
<h3 id="_spring_aop">Spring AOP</h3>
<div class="paragraph">
<p>Spring AOP is a lightweight implementation of AOP, designed specifically for use with Spring&#8217;s IoC (Inversion of Control) container. It supports runtime weaving and is particularly well-suited for managing cross-cutting concerns in Spring-based applications.</p>
</div>
<div class="paragraph">
<p>Example: Logging with Spring AOP</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // Pointcut to match all methods in the service package
    @Pointcut("execution(* com.example.service..*(..))")
    public void serviceMethods() {}

    // Before advice to log method execution
    @Before("serviceMethods()")
    public void logBeforeMethod() {
        System.out.println("Logging: Service method invoked.");
    }
}

@Component
public class UserService {
    public void createUser(String name) {
        System.out.println("User created: " + name);
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Spring AOP integrates easily into Spring projects and relies on proxies for weaving, offering developers a clean and Spring-friendly approach to AOP.</p>
</div>
</div>
<div class="sect2">
<h3 id="_quarkus">Quarkus</h3>
<div class="paragraph">
<p>Quarkus, known for its Kubernetes-native Java stack, also supports AOP but in a simplified and efficient way compared to traditional implementations.</p>
</div>
<div class="paragraph">
<p>Example: Logging with Quarkus AOP</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-java" data-lang="java">import io.quarkus.arc.Arc;
import javax.annotation.Priority;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

@Interceptor
@Priority(1)
@Logging
public class LoggingInterceptor {

    @AroundInvoke
    public Object logInvocation(InvocationContext context) throws Exception {
        System.out.println("Logging: Method called - " + context.getMethod().getName());
        return context.proceed();
    }
}

// Custom annotation to apply the interceptor
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@InterceptorBinding
public @interface Logging {}

@Logging
public class UserService {
    public void createUser(String name) {
        System.out.println("User created: " + name);
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Quarkus brings AOP into the modern world of cloud-native, containerized Java applications. It uses <strong>build-time weaving</strong> to reduce the runtime overhead and optimize performance, which is crucial for microservices running in environments like Kubernetes. By leveraging <strong>CDI</strong> (Contexts and Dependency Injection), Quarkus simplifies the use of AOP, making it an excellent choice for developers building lightweight, fast, and highly performant Java applications in the cloud.</p>
</div>
</div>
<div class="sect2">
<h3 id="_final_note">Final Note</h3>
<div class="ulist">
<ul>
<li>
<p><strong>AspectJ</strong>: Best suited for complex, large-scale enterprise applications where flexibility and deep integration into the application’s lifecycle are required. The learning curve is steeper, and performance may be a consideration, but its capabilities in fine-grained join points and weaving techniques make it ideal for scenarios where AOP is deeply integrated into the system&#8217;s architecture.</p>
</li>
<li>
<p><strong>Spring AOP</strong>: Excellent for Spring-based applications where developers are looking for a lightweight, simple solution to apply cross-cutting concerns. It’s great for common needs such as logging and transaction management, but it’s limited to Spring-managed beans and doesn’t support all the advanced weaving options that AspectJ offers.</p>
</li>
<li>
<p><strong>Quarkus AOP</strong>: A perfect choice for cloud-native, containerized applications. If you’re building microservices or applications with performance-critical requirements, Quarkus is optimized for minimal runtime overhead and integrates well with modern development workflows like Kubernetes.</p>
</li>
</ul>
</div>
</div>
<div class="sect1">
<h2 id="_source">Source</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>[What is AOP? ](<a href="https://www.spiceworks.com/tech/devops/articles/what-is-aop/" class="bare">https://www.spiceworks.com/tech/devops/articles/what-is-aop/</a>)</p>
</li>
<li>
<p>[Spring AOP Documentation](<a href="https://docs.spring.io/spring-framework/reference/core/aop.html/" class="bare">https://docs.spring.io/spring-framework/reference/core/aop.html/</a>)</p>
</li>
<li>
<p>[AspectJ in Action - Manning](<a href="https://www.baeldung.com/aspectj" class="bare">https://www.baeldung.com/aspectj</a>)</p>
</li>
</ul>
</div>
</div>
</div>
<]]></content:encoded>
					
		
		
			</item>
        
	</channel>
</rss>


